1 /*
2 * SAX2.c : Default SAX2 handler to build a tree.
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <daniel@veillard.com>
7 */
8
9
10 #define IN_LIBXML
11 #include "libxml.h"
12 #include <stdlib.h>
13 #include <string.h>
14 #include <limits.h>
15 #include <stddef.h>
16 #include <libxml/xmlmemory.h>
17 #include <libxml/tree.h>
18 #include <libxml/parser.h>
19 #include <libxml/parserInternals.h>
20 #include <libxml/valid.h>
21 #include <libxml/entities.h>
22 #include <libxml/xmlerror.h>
23 #include <libxml/debugXML.h>
24 #include <libxml/xmlIO.h>
25 #include <libxml/SAX.h>
26 #include <libxml/uri.h>
27 #include <libxml/valid.h>
28 #include <libxml/HTMLtree.h>
29 #include <libxml/globals.h>
30
31 /* #define DEBUG_SAX2 */
32 /* #define DEBUG_SAX2_TREE */
33
34 /**
35 * TODO:
36 *
37 * macro to flag unimplemented blocks
38 * XML_CATALOG_PREFER user env to select between system/public preferred
39 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
40 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
41 *> values "system" and "public". I have made the default be "system" to
42 *> match yours.
43 */
44 #define TODO \
45 xmlGenericError(xmlGenericErrorContext, \
46 "Unimplemented block at %s:%d\n", \
47 __FILE__, __LINE__);
48
49 /*
50 * xmlSAX2ErrMemory:
51 * @ctxt: an XML validation parser context
52 * @msg: a string to accompany the error message
53 */
54 static void LIBXML_ATTR_FORMAT(2,0)
xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt,const char * msg)55 xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) {
56 xmlStructuredErrorFunc schannel = NULL;
57 const char *str1 = "out of memory\n";
58
59 if (ctxt != NULL) {
60 ctxt->errNo = XML_ERR_NO_MEMORY;
61 if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
62 schannel = ctxt->sax->serror;
63 __xmlRaiseError(schannel,
64 ctxt->vctxt.error, ctxt->vctxt.userData,
65 ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
66 XML_ERR_ERROR, NULL, 0, (const char *) str1,
67 NULL, NULL, 0, 0,
68 msg, (const char *) str1, NULL);
69 ctxt->errNo = XML_ERR_NO_MEMORY;
70 ctxt->instate = XML_PARSER_EOF;
71 ctxt->disableSAX = 1;
72 } else {
73 __xmlRaiseError(schannel,
74 NULL, NULL,
75 ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
76 XML_ERR_ERROR, NULL, 0, (const char *) str1,
77 NULL, NULL, 0, 0,
78 msg, (const char *) str1, NULL);
79 }
80 }
81
82 /**
83 * xmlValidError:
84 * @ctxt: an XML validation parser context
85 * @error: the error number
86 * @msg: the error message
87 * @str1: extra data
88 * @str2: extra data
89 *
90 * Handle a validation error
91 */
92 static void LIBXML_ATTR_FORMAT(3,0)
xmlErrValid(xmlParserCtxtPtr ctxt,xmlParserErrors error,const char * msg,const char * str1,const char * str2)93 xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error,
94 const char *msg, const char *str1, const char *str2)
95 {
96 xmlStructuredErrorFunc schannel = NULL;
97
98 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
99 (ctxt->instate == XML_PARSER_EOF))
100 return;
101 if (ctxt != NULL) {
102 ctxt->errNo = error;
103 if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
104 schannel = ctxt->sax->serror;
105 __xmlRaiseError(schannel,
106 ctxt->vctxt.error, ctxt->vctxt.userData,
107 ctxt, NULL, XML_FROM_DTD, error,
108 XML_ERR_ERROR, NULL, 0, (const char *) str1,
109 (const char *) str2, NULL, 0, 0,
110 msg, (const char *) str1, (const char *) str2);
111 ctxt->valid = 0;
112 } else {
113 __xmlRaiseError(schannel,
114 NULL, NULL,
115 ctxt, NULL, XML_FROM_DTD, error,
116 XML_ERR_ERROR, NULL, 0, (const char *) str1,
117 (const char *) str2, NULL, 0, 0,
118 msg, (const char *) str1, (const char *) str2);
119 }
120 }
121
122 /**
123 * xmlFatalErrMsg:
124 * @ctxt: an XML parser context
125 * @error: the error number
126 * @msg: the error message
127 * @str1: an error string
128 * @str2: an error string
129 *
130 * Handle a fatal parser error, i.e. violating Well-Formedness constraints
131 */
132 static void LIBXML_ATTR_FORMAT(3,0)
xmlFatalErrMsg(xmlParserCtxtPtr ctxt,xmlParserErrors error,const char * msg,const xmlChar * str1,const xmlChar * str2)133 xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
134 const char *msg, const xmlChar *str1, const xmlChar *str2)
135 {
136 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
137 (ctxt->instate == XML_PARSER_EOF))
138 return;
139 if (ctxt != NULL)
140 ctxt->errNo = error;
141 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
142 XML_ERR_FATAL, NULL, 0,
143 (const char *) str1, (const char *) str2,
144 NULL, 0, 0, msg, str1, str2);
145 if (ctxt != NULL) {
146 ctxt->wellFormed = 0;
147 ctxt->valid = 0;
148 if (ctxt->recovery == 0)
149 ctxt->disableSAX = 1;
150 }
151 }
152
153 /**
154 * xmlWarnMsg:
155 * @ctxt: an XML parser context
156 * @error: the error number
157 * @msg: the error message
158 * @str1: an error string
159 * @str2: an error string
160 *
161 * Handle a parser warning
162 */
163 static void LIBXML_ATTR_FORMAT(3,0)
xmlWarnMsg(xmlParserCtxtPtr ctxt,xmlParserErrors error,const char * msg,const xmlChar * str1)164 xmlWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
165 const char *msg, const xmlChar *str1)
166 {
167 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
168 (ctxt->instate == XML_PARSER_EOF))
169 return;
170 if (ctxt != NULL)
171 ctxt->errNo = error;
172 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
173 XML_ERR_WARNING, NULL, 0,
174 (const char *) str1, NULL,
175 NULL, 0, 0, msg, str1);
176 }
177
178 /**
179 * xmlNsWarnMsg:
180 * @ctxt: an XML parser context
181 * @error: the error number
182 * @msg: the error message
183 * @str1: an error string
184 *
185 * Handle a namespace warning
186 */
187 static void LIBXML_ATTR_FORMAT(3,0)
xmlNsWarnMsg(xmlParserCtxtPtr ctxt,xmlParserErrors error,const char * msg,const xmlChar * str1,const xmlChar * str2)188 xmlNsWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
189 const char *msg, const xmlChar *str1, const xmlChar *str2)
190 {
191 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
192 (ctxt->instate == XML_PARSER_EOF))
193 return;
194 if (ctxt != NULL)
195 ctxt->errNo = error;
196 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
197 XML_ERR_WARNING, NULL, 0,
198 (const char *) str1, (const char *) str2,
199 NULL, 0, 0, msg, str1, str2);
200 }
201
202 /**
203 * xmlSAX2GetPublicId:
204 * @ctx: the user data (XML parser context)
205 *
206 * Provides the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
207 *
208 * Returns a xmlChar *
209 */
210 const xmlChar *
xmlSAX2GetPublicId(void * ctx ATTRIBUTE_UNUSED)211 xmlSAX2GetPublicId(void *ctx ATTRIBUTE_UNUSED)
212 {
213 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
214 return(NULL);
215 }
216
217 /**
218 * xmlSAX2GetSystemId:
219 * @ctx: the user data (XML parser context)
220 *
221 * Provides the system ID, basically URL or filename e.g.
222 * http://www.sgmlsource.com/dtds/memo.dtd
223 *
224 * Returns a xmlChar *
225 */
226 const xmlChar *
xmlSAX2GetSystemId(void * ctx)227 xmlSAX2GetSystemId(void *ctx)
228 {
229 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
230 if ((ctx == NULL) || (ctxt->input == NULL)) return(NULL);
231 return((const xmlChar *) ctxt->input->filename);
232 }
233
234 /**
235 * xmlSAX2GetLineNumber:
236 * @ctx: the user data (XML parser context)
237 *
238 * Provide the line number of the current parsing point.
239 *
240 * Returns an int
241 */
242 int
xmlSAX2GetLineNumber(void * ctx)243 xmlSAX2GetLineNumber(void *ctx)
244 {
245 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
246 if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
247 return(ctxt->input->line);
248 }
249
250 /**
251 * xmlSAX2GetColumnNumber:
252 * @ctx: the user data (XML parser context)
253 *
254 * Provide the column number of the current parsing point.
255 *
256 * Returns an int
257 */
258 int
xmlSAX2GetColumnNumber(void * ctx)259 xmlSAX2GetColumnNumber(void *ctx)
260 {
261 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
262 if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
263 return(ctxt->input->col);
264 }
265
266 /**
267 * xmlSAX2IsStandalone:
268 * @ctx: the user data (XML parser context)
269 *
270 * Is this document tagged standalone ?
271 *
272 * Returns 1 if true
273 */
274 int
xmlSAX2IsStandalone(void * ctx)275 xmlSAX2IsStandalone(void *ctx)
276 {
277 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
278 if ((ctx == NULL) || (ctxt->myDoc == NULL)) return(0);
279 return(ctxt->myDoc->standalone == 1);
280 }
281
282 /**
283 * xmlSAX2HasInternalSubset:
284 * @ctx: the user data (XML parser context)
285 *
286 * Does this document has an internal subset
287 *
288 * Returns 1 if true
289 */
290 int
xmlSAX2HasInternalSubset(void * ctx)291 xmlSAX2HasInternalSubset(void *ctx)
292 {
293 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
294 if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
295 return(ctxt->myDoc->intSubset != NULL);
296 }
297
298 /**
299 * xmlSAX2HasExternalSubset:
300 * @ctx: the user data (XML parser context)
301 *
302 * Does this document has an external subset
303 *
304 * Returns 1 if true
305 */
306 int
xmlSAX2HasExternalSubset(void * ctx)307 xmlSAX2HasExternalSubset(void *ctx)
308 {
309 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
310 if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
311 return(ctxt->myDoc->extSubset != NULL);
312 }
313
314 /**
315 * xmlSAX2InternalSubset:
316 * @ctx: the user data (XML parser context)
317 * @name: the root element name
318 * @ExternalID: the external ID
319 * @SystemID: the SYSTEM ID (e.g. filename or URL)
320 *
321 * Callback on internal subset declaration.
322 */
323 void
xmlSAX2InternalSubset(void * ctx,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)324 xmlSAX2InternalSubset(void *ctx, const xmlChar *name,
325 const xmlChar *ExternalID, const xmlChar *SystemID)
326 {
327 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
328 xmlDtdPtr dtd;
329 if (ctx == NULL) return;
330 #ifdef DEBUG_SAX
331 xmlGenericError(xmlGenericErrorContext,
332 "SAX.xmlSAX2InternalSubset(%s, %s, %s)\n",
333 name, ExternalID, SystemID);
334 #endif
335
336 if (ctxt->myDoc == NULL)
337 return;
338 dtd = xmlGetIntSubset(ctxt->myDoc);
339 if (dtd != NULL) {
340 if (ctxt->html)
341 return;
342 xmlUnlinkNode((xmlNodePtr) dtd);
343 xmlFreeDtd(dtd);
344 ctxt->myDoc->intSubset = NULL;
345 }
346 ctxt->myDoc->intSubset =
347 xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
348 if (ctxt->myDoc->intSubset == NULL)
349 xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset");
350 }
351
352 /**
353 * xmlSAX2ExternalSubset:
354 * @ctx: the user data (XML parser context)
355 * @name: the root element name
356 * @ExternalID: the external ID
357 * @SystemID: the SYSTEM ID (e.g. filename or URL)
358 *
359 * Callback on external subset declaration.
360 */
361 void
xmlSAX2ExternalSubset(void * ctx,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)362 xmlSAX2ExternalSubset(void *ctx, const xmlChar *name,
363 const xmlChar *ExternalID, const xmlChar *SystemID)
364 {
365 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
366 if (ctx == NULL) return;
367 #ifdef DEBUG_SAX
368 xmlGenericError(xmlGenericErrorContext,
369 "SAX.xmlSAX2ExternalSubset(%s, %s, %s)\n",
370 name, ExternalID, SystemID);
371 #endif
372 if (((ExternalID != NULL) || (SystemID != NULL)) &&
373 (((ctxt->validate) || (ctxt->loadsubset != 0)) &&
374 (ctxt->wellFormed && ctxt->myDoc))) {
375 /*
376 * Try to fetch and parse the external subset.
377 */
378 xmlParserInputPtr oldinput;
379 int oldinputNr;
380 int oldinputMax;
381 xmlParserInputPtr *oldinputTab;
382 xmlParserInputPtr input = NULL;
383 xmlCharEncoding enc;
384 int oldcharset;
385 const xmlChar *oldencoding;
386
387 /*
388 * Ask the Entity resolver to load the damn thing
389 */
390 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
391 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
392 SystemID);
393 if (input == NULL) {
394 return;
395 }
396
397 xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
398
399 /*
400 * make sure we won't destroy the main document context
401 */
402 oldinput = ctxt->input;
403 oldinputNr = ctxt->inputNr;
404 oldinputMax = ctxt->inputMax;
405 oldinputTab = ctxt->inputTab;
406 oldcharset = ctxt->charset;
407 oldencoding = ctxt->encoding;
408 ctxt->encoding = NULL;
409
410 ctxt->inputTab = (xmlParserInputPtr *)
411 xmlMalloc(5 * sizeof(xmlParserInputPtr));
412 if (ctxt->inputTab == NULL) {
413 xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset");
414 ctxt->input = oldinput;
415 ctxt->inputNr = oldinputNr;
416 ctxt->inputMax = oldinputMax;
417 ctxt->inputTab = oldinputTab;
418 ctxt->charset = oldcharset;
419 ctxt->encoding = oldencoding;
420 return;
421 }
422 ctxt->inputNr = 0;
423 ctxt->inputMax = 5;
424 ctxt->input = NULL;
425 xmlPushInput(ctxt, input);
426
427 /*
428 * On the fly encoding conversion if needed
429 */
430 if (ctxt->input->length >= 4) {
431 enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
432 xmlSwitchEncoding(ctxt, enc);
433 }
434
435 if (input->filename == NULL)
436 input->filename = (char *) xmlCanonicPath(SystemID);
437 input->line = 1;
438 input->col = 1;
439 input->base = ctxt->input->cur;
440 input->cur = ctxt->input->cur;
441 input->free = NULL;
442
443 /*
444 * let's parse that entity knowing it's an external subset.
445 */
446 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
447
448 /*
449 * Free up the external entities
450 */
451
452 while (ctxt->inputNr > 1)
453 xmlPopInput(ctxt);
454 xmlFreeInputStream(ctxt->input);
455 xmlFree(ctxt->inputTab);
456
457 /*
458 * Restore the parsing context of the main entity
459 */
460 ctxt->input = oldinput;
461 ctxt->inputNr = oldinputNr;
462 ctxt->inputMax = oldinputMax;
463 ctxt->inputTab = oldinputTab;
464 ctxt->charset = oldcharset;
465 if ((ctxt->encoding != NULL) &&
466 ((ctxt->dict == NULL) ||
467 (!xmlDictOwns(ctxt->dict, ctxt->encoding))))
468 xmlFree((xmlChar *) ctxt->encoding);
469 ctxt->encoding = oldencoding;
470 /* ctxt->wellFormed = oldwellFormed; */
471 }
472 }
473
474 /**
475 * xmlSAX2ResolveEntity:
476 * @ctx: the user data (XML parser context)
477 * @publicId: The public ID of the entity
478 * @systemId: The system ID of the entity
479 *
480 * The entity loader, to control the loading of external entities,
481 * the application can either:
482 * - override this xmlSAX2ResolveEntity() callback in the SAX block
483 * - or better use the xmlSetExternalEntityLoader() function to
484 * set up it's own entity resolution routine
485 *
486 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
487 */
488 xmlParserInputPtr
xmlSAX2ResolveEntity(void * ctx,const xmlChar * publicId,const xmlChar * systemId)489 xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
490 {
491 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
492 xmlParserInputPtr ret;
493 xmlChar *URI;
494 const char *base = NULL;
495
496 if (ctx == NULL) return(NULL);
497 if (ctxt->input != NULL)
498 base = ctxt->input->filename;
499 if (base == NULL)
500 base = ctxt->directory;
501
502 URI = xmlBuildURI(systemId, (const xmlChar *) base);
503
504 #ifdef DEBUG_SAX
505 xmlGenericError(xmlGenericErrorContext,
506 "SAX.xmlSAX2ResolveEntity(%s, %s)\n", publicId, systemId);
507 #endif
508
509 ret = xmlLoadExternalEntity((const char *) URI,
510 (const char *) publicId, ctxt);
511 if (URI != NULL)
512 xmlFree(URI);
513 return(ret);
514 }
515
516 /**
517 * xmlSAX2GetEntity:
518 * @ctx: the user data (XML parser context)
519 * @name: The entity name
520 *
521 * Get an entity by name
522 *
523 * Returns the xmlEntityPtr if found.
524 */
525 xmlEntityPtr
xmlSAX2GetEntity(void * ctx,const xmlChar * name)526 xmlSAX2GetEntity(void *ctx, const xmlChar *name)
527 {
528 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
529 xmlEntityPtr ret = NULL;
530
531 if (ctx == NULL) return(NULL);
532 #ifdef DEBUG_SAX
533 xmlGenericError(xmlGenericErrorContext,
534 "SAX.xmlSAX2GetEntity(%s)\n", name);
535 #endif
536
537 if (ctxt->inSubset == 0) {
538 ret = xmlGetPredefinedEntity(name);
539 if (ret != NULL)
540 return(ret);
541 }
542 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->standalone == 1)) {
543 if (ctxt->inSubset == 2) {
544 ctxt->myDoc->standalone = 0;
545 ret = xmlGetDocEntity(ctxt->myDoc, name);
546 ctxt->myDoc->standalone = 1;
547 } else {
548 ret = xmlGetDocEntity(ctxt->myDoc, name);
549 if (ret == NULL) {
550 ctxt->myDoc->standalone = 0;
551 ret = xmlGetDocEntity(ctxt->myDoc, name);
552 if (ret != NULL) {
553 xmlFatalErrMsg(ctxt, XML_ERR_NOT_STANDALONE,
554 "Entity(%s) document marked standalone but requires external subset\n",
555 name, NULL);
556 }
557 ctxt->myDoc->standalone = 1;
558 }
559 }
560 } else {
561 ret = xmlGetDocEntity(ctxt->myDoc, name);
562 }
563 return(ret);
564 }
565
566 /**
567 * xmlSAX2GetParameterEntity:
568 * @ctx: the user data (XML parser context)
569 * @name: The entity name
570 *
571 * Get a parameter entity by name
572 *
573 * Returns the xmlEntityPtr if found.
574 */
575 xmlEntityPtr
xmlSAX2GetParameterEntity(void * ctx,const xmlChar * name)576 xmlSAX2GetParameterEntity(void *ctx, const xmlChar *name)
577 {
578 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
579 xmlEntityPtr ret;
580
581 if (ctx == NULL) return(NULL);
582 #ifdef DEBUG_SAX
583 xmlGenericError(xmlGenericErrorContext,
584 "SAX.xmlSAX2GetParameterEntity(%s)\n", name);
585 #endif
586
587 ret = xmlGetParameterEntity(ctxt->myDoc, name);
588 return(ret);
589 }
590
591
592 /**
593 * xmlSAX2EntityDecl:
594 * @ctx: the user data (XML parser context)
595 * @name: the entity name
596 * @type: the entity type
597 * @publicId: The public ID of the entity
598 * @systemId: The system ID of the entity
599 * @content: the entity value (without processing).
600 *
601 * An entity definition has been parsed
602 */
603 void
xmlSAX2EntityDecl(void * ctx,const xmlChar * name,int type,const xmlChar * publicId,const xmlChar * systemId,xmlChar * content)604 xmlSAX2EntityDecl(void *ctx, const xmlChar *name, int type,
605 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
606 {
607 xmlEntityPtr ent;
608 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
609
610 if (ctx == NULL) return;
611 #ifdef DEBUG_SAX
612 xmlGenericError(xmlGenericErrorContext,
613 "SAX.xmlSAX2EntityDecl(%s, %d, %s, %s, %s)\n",
614 name, type, publicId, systemId, content);
615 #endif
616 if (ctxt->inSubset == 1) {
617 ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
618 systemId, content);
619 if ((ent == NULL) && (ctxt->pedantic))
620 xmlWarnMsg(ctxt, XML_WAR_ENTITY_REDEFINED,
621 "Entity(%s) already defined in the internal subset\n",
622 name);
623 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
624 xmlChar *URI;
625 const char *base = NULL;
626
627 if (ctxt->input != NULL)
628 base = ctxt->input->filename;
629 if (base == NULL)
630 base = ctxt->directory;
631
632 URI = xmlBuildURI(systemId, (const xmlChar *) base);
633 ent->URI = URI;
634 }
635 } else if (ctxt->inSubset == 2) {
636 ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
637 systemId, content);
638 if ((ent == NULL) && (ctxt->pedantic) &&
639 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
640 ctxt->sax->warning(ctxt->userData,
641 "Entity(%s) already defined in the external subset\n", name);
642 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
643 xmlChar *URI;
644 const char *base = NULL;
645
646 if (ctxt->input != NULL)
647 base = ctxt->input->filename;
648 if (base == NULL)
649 base = ctxt->directory;
650
651 URI = xmlBuildURI(systemId, (const xmlChar *) base);
652 ent->URI = URI;
653 }
654 } else {
655 xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_PROCESSING,
656 "SAX.xmlSAX2EntityDecl(%s) called while not in subset\n",
657 name, NULL);
658 }
659 }
660
661 /**
662 * xmlSAX2AttributeDecl:
663 * @ctx: the user data (XML parser context)
664 * @elem: the name of the element
665 * @fullname: the attribute name
666 * @type: the attribute type
667 * @def: the type of default value
668 * @defaultValue: the attribute default value
669 * @tree: the tree of enumerated value set
670 *
671 * An attribute definition has been parsed
672 */
673 void
xmlSAX2AttributeDecl(void * ctx,const xmlChar * elem,const xmlChar * fullname,int type,int def,const xmlChar * defaultValue,xmlEnumerationPtr tree)674 xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
675 int type, int def, const xmlChar *defaultValue,
676 xmlEnumerationPtr tree)
677 {
678 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
679 xmlAttributePtr attr;
680 xmlChar *name = NULL, *prefix = NULL;
681
682 /* Avoid unused variable warning if features are disabled. */
683 (void) attr;
684
685 if ((ctxt == NULL) || (ctxt->myDoc == NULL))
686 return;
687
688 #ifdef DEBUG_SAX
689 xmlGenericError(xmlGenericErrorContext,
690 "SAX.xmlSAX2AttributeDecl(%s, %s, %d, %d, %s, ...)\n",
691 elem, fullname, type, def, defaultValue);
692 #endif
693 if ((xmlStrEqual(fullname, BAD_CAST "xml:id")) &&
694 (type != XML_ATTRIBUTE_ID)) {
695 /*
696 * Raise the error but keep the validity flag
697 */
698 int tmp = ctxt->valid;
699 xmlErrValid(ctxt, XML_DTD_XMLID_TYPE,
700 "xml:id : attribute type should be ID\n", NULL, NULL);
701 ctxt->valid = tmp;
702 }
703 /* TODO: optimize name/prefix allocation */
704 name = xmlSplitQName(ctxt, fullname, &prefix);
705 ctxt->vctxt.valid = 1;
706 if (ctxt->inSubset == 1)
707 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
708 name, prefix, (xmlAttributeType) type,
709 (xmlAttributeDefault) def, defaultValue, tree);
710 else if (ctxt->inSubset == 2)
711 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
712 name, prefix, (xmlAttributeType) type,
713 (xmlAttributeDefault) def, defaultValue, tree);
714 else {
715 xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
716 "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n",
717 name, NULL);
718 xmlFree(name);
719 xmlFreeEnumeration(tree);
720 return;
721 }
722 #ifdef LIBXML_VALID_ENABLED
723 if (ctxt->vctxt.valid == 0)
724 ctxt->valid = 0;
725 if ((attr != NULL) && (ctxt->validate) && (ctxt->wellFormed) &&
726 (ctxt->myDoc->intSubset != NULL))
727 ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
728 attr);
729 #endif /* LIBXML_VALID_ENABLED */
730 if (prefix != NULL)
731 xmlFree(prefix);
732 if (name != NULL)
733 xmlFree(name);
734 }
735
736 /**
737 * xmlSAX2ElementDecl:
738 * @ctx: the user data (XML parser context)
739 * @name: the element name
740 * @type: the element type
741 * @content: the element value tree
742 *
743 * An element definition has been parsed
744 */
745 void
xmlSAX2ElementDecl(void * ctx,const xmlChar * name,int type,xmlElementContentPtr content)746 xmlSAX2ElementDecl(void *ctx, const xmlChar * name, int type,
747 xmlElementContentPtr content)
748 {
749 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
750 xmlElementPtr elem = NULL;
751
752 /* Avoid unused variable warning if features are disabled. */
753 (void) elem;
754
755 if ((ctxt == NULL) || (ctxt->myDoc == NULL))
756 return;
757
758 #ifdef DEBUG_SAX
759 xmlGenericError(xmlGenericErrorContext,
760 "SAX.xmlSAX2ElementDecl(%s, %d, ...)\n", name, type);
761 #endif
762
763 if (ctxt->inSubset == 1)
764 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
765 name, (xmlElementTypeVal) type, content);
766 else if (ctxt->inSubset == 2)
767 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
768 name, (xmlElementTypeVal) type, content);
769 else {
770 xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
771 "SAX.xmlSAX2ElementDecl(%s) called while not in subset\n",
772 name, NULL);
773 return;
774 }
775 #ifdef LIBXML_VALID_ENABLED
776 if (elem == NULL)
777 ctxt->valid = 0;
778 if (ctxt->validate && ctxt->wellFormed &&
779 ctxt->myDoc && ctxt->myDoc->intSubset)
780 ctxt->valid &=
781 xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
782 #endif /* LIBXML_VALID_ENABLED */
783 }
784
785 /**
786 * xmlSAX2NotationDecl:
787 * @ctx: the user data (XML parser context)
788 * @name: The name of the notation
789 * @publicId: The public ID of the entity
790 * @systemId: The system ID of the entity
791 *
792 * What to do when a notation declaration has been parsed.
793 */
794 void
xmlSAX2NotationDecl(void * ctx,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)795 xmlSAX2NotationDecl(void *ctx, const xmlChar *name,
796 const xmlChar *publicId, const xmlChar *systemId)
797 {
798 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
799 xmlNotationPtr nota = NULL;
800
801 /* Avoid unused variable warning if features are disabled. */
802 (void) nota;
803
804 if ((ctxt == NULL) || (ctxt->myDoc == NULL))
805 return;
806
807 #ifdef DEBUG_SAX
808 xmlGenericError(xmlGenericErrorContext,
809 "SAX.xmlSAX2NotationDecl(%s, %s, %s)\n", name, publicId, systemId);
810 #endif
811
812 if ((publicId == NULL) && (systemId == NULL)) {
813 xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING,
814 "SAX.xmlSAX2NotationDecl(%s) externalID or PublicID missing\n",
815 name, NULL);
816 return;
817 } else if (ctxt->inSubset == 1)
818 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
819 publicId, systemId);
820 else if (ctxt->inSubset == 2)
821 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, name,
822 publicId, systemId);
823 else {
824 xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING,
825 "SAX.xmlSAX2NotationDecl(%s) called while not in subset\n",
826 name, NULL);
827 return;
828 }
829 #ifdef LIBXML_VALID_ENABLED
830 if (nota == NULL) ctxt->valid = 0;
831 if ((ctxt->validate) && (ctxt->wellFormed) &&
832 (ctxt->myDoc->intSubset != NULL))
833 ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
834 nota);
835 #endif /* LIBXML_VALID_ENABLED */
836 }
837
838 /**
839 * xmlSAX2UnparsedEntityDecl:
840 * @ctx: the user data (XML parser context)
841 * @name: The name of the entity
842 * @publicId: The public ID of the entity
843 * @systemId: The system ID of the entity
844 * @notationName: the name of the notation
845 *
846 * What to do when an unparsed entity declaration is parsed
847 */
848 void
xmlSAX2UnparsedEntityDecl(void * ctx,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId,const xmlChar * notationName)849 xmlSAX2UnparsedEntityDecl(void *ctx, const xmlChar *name,
850 const xmlChar *publicId, const xmlChar *systemId,
851 const xmlChar *notationName)
852 {
853 xmlEntityPtr ent;
854 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
855 if (ctx == NULL) return;
856 #ifdef DEBUG_SAX
857 xmlGenericError(xmlGenericErrorContext,
858 "SAX.xmlSAX2UnparsedEntityDecl(%s, %s, %s, %s)\n",
859 name, publicId, systemId, notationName);
860 #endif
861 if (ctxt->inSubset == 1) {
862 ent = xmlAddDocEntity(ctxt->myDoc, name,
863 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
864 publicId, systemId, notationName);
865 if ((ent == NULL) && (ctxt->pedantic) &&
866 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
867 ctxt->sax->warning(ctxt->userData,
868 "Entity(%s) already defined in the internal subset\n", name);
869 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
870 xmlChar *URI;
871 const char *base = NULL;
872
873 if (ctxt->input != NULL)
874 base = ctxt->input->filename;
875 if (base == NULL)
876 base = ctxt->directory;
877
878 URI = xmlBuildURI(systemId, (const xmlChar *) base);
879 ent->URI = URI;
880 }
881 } else if (ctxt->inSubset == 2) {
882 ent = xmlAddDtdEntity(ctxt->myDoc, name,
883 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
884 publicId, systemId, notationName);
885 if ((ent == NULL) && (ctxt->pedantic) &&
886 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
887 ctxt->sax->warning(ctxt->userData,
888 "Entity(%s) already defined in the external subset\n", name);
889 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
890 xmlChar *URI;
891 const char *base = NULL;
892
893 if (ctxt->input != NULL)
894 base = ctxt->input->filename;
895 if (base == NULL)
896 base = ctxt->directory;
897
898 URI = xmlBuildURI(systemId, (const xmlChar *) base);
899 ent->URI = URI;
900 }
901 } else {
902 xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
903 "SAX.xmlSAX2UnparsedEntityDecl(%s) called while not in subset\n",
904 name, NULL);
905 }
906 }
907
908 /**
909 * xmlSAX2SetDocumentLocator:
910 * @ctx: the user data (XML parser context)
911 * @loc: A SAX Locator
912 *
913 * Receive the document locator at startup, actually xmlDefaultSAXLocator
914 * Everything is available on the context, so this is useless in our case.
915 */
916 void
xmlSAX2SetDocumentLocator(void * ctx ATTRIBUTE_UNUSED,xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)917 xmlSAX2SetDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
918 {
919 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
920 #ifdef DEBUG_SAX
921 xmlGenericError(xmlGenericErrorContext,
922 "SAX.xmlSAX2SetDocumentLocator()\n");
923 #endif
924 }
925
926 /**
927 * xmlSAX2StartDocument:
928 * @ctx: the user data (XML parser context)
929 *
930 * called when the document start being processed.
931 */
932 void
xmlSAX2StartDocument(void * ctx)933 xmlSAX2StartDocument(void *ctx)
934 {
935 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
936 xmlDocPtr doc;
937
938 if (ctx == NULL) return;
939
940 #ifdef DEBUG_SAX
941 xmlGenericError(xmlGenericErrorContext,
942 "SAX.xmlSAX2StartDocument()\n");
943 #endif
944 if (ctxt->html) {
945 #ifdef LIBXML_HTML_ENABLED
946 if (ctxt->myDoc == NULL)
947 ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
948 if (ctxt->myDoc == NULL) {
949 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
950 return;
951 }
952 ctxt->myDoc->properties = XML_DOC_HTML;
953 ctxt->myDoc->parseFlags = ctxt->options;
954 #else
955 xmlGenericError(xmlGenericErrorContext,
956 "libxml2 built without HTML support\n");
957 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
958 ctxt->instate = XML_PARSER_EOF;
959 ctxt->disableSAX = 1;
960 return;
961 #endif
962 } else {
963 doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
964 if (doc != NULL) {
965 doc->properties = 0;
966 if (ctxt->options & XML_PARSE_OLD10)
967 doc->properties |= XML_DOC_OLD10;
968 doc->parseFlags = ctxt->options;
969 if (ctxt->encoding != NULL)
970 doc->encoding = xmlStrdup(ctxt->encoding);
971 else
972 doc->encoding = NULL;
973 doc->standalone = ctxt->standalone;
974 } else {
975 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
976 return;
977 }
978 if ((ctxt->dictNames) && (doc != NULL)) {
979 doc->dict = ctxt->dict;
980 xmlDictReference(doc->dict);
981 }
982 }
983 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
984 (ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
985 ctxt->myDoc->URL = xmlPathToURI((const xmlChar *)ctxt->input->filename);
986 if (ctxt->myDoc->URL == NULL)
987 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
988 }
989 }
990
991 /**
992 * xmlSAX2EndDocument:
993 * @ctx: the user data (XML parser context)
994 *
995 * called when the document end has been detected.
996 */
997 void
xmlSAX2EndDocument(void * ctx)998 xmlSAX2EndDocument(void *ctx)
999 {
1000 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1001 #ifdef DEBUG_SAX
1002 xmlGenericError(xmlGenericErrorContext,
1003 "SAX.xmlSAX2EndDocument()\n");
1004 #endif
1005 if (ctx == NULL) return;
1006 #ifdef LIBXML_VALID_ENABLED
1007 if (ctxt->validate && ctxt->wellFormed &&
1008 ctxt->myDoc && ctxt->myDoc->intSubset)
1009 ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc);
1010 #endif /* LIBXML_VALID_ENABLED */
1011
1012 /*
1013 * Grab the encoding if it was added on-the-fly
1014 */
1015 if ((ctxt->encoding != NULL) && (ctxt->myDoc != NULL) &&
1016 (ctxt->myDoc->encoding == NULL)) {
1017 ctxt->myDoc->encoding = ctxt->encoding;
1018 ctxt->encoding = NULL;
1019 }
1020 if ((ctxt->inputTab != NULL) &&
1021 (ctxt->inputNr > 0) && (ctxt->inputTab[0] != NULL) &&
1022 (ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
1023 (ctxt->myDoc->encoding == NULL)) {
1024 ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
1025 }
1026 if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) &&
1027 (ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) {
1028 ctxt->myDoc->charset = ctxt->charset;
1029 }
1030 }
1031
1032 #if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
1033 /**
1034 * xmlNsErrMsg:
1035 * @ctxt: an XML parser context
1036 * @error: the error number
1037 * @msg: the error message
1038 * @str1: an error string
1039 * @str2: an error string
1040 *
1041 * Handle a namespace error
1042 */
1043 static void LIBXML_ATTR_FORMAT(3,0)
xmlNsErrMsg(xmlParserCtxtPtr ctxt,xmlParserErrors error,const char * msg,const xmlChar * str1,const xmlChar * str2)1044 xmlNsErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
1045 const char *msg, const xmlChar *str1, const xmlChar *str2)
1046 {
1047 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
1048 (ctxt->instate == XML_PARSER_EOF))
1049 return;
1050 if (ctxt != NULL)
1051 ctxt->errNo = error;
1052 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
1053 XML_ERR_ERROR, NULL, 0,
1054 (const char *) str1, (const char *) str2,
1055 NULL, 0, 0, msg, str1, str2);
1056 }
1057
1058 /**
1059 * xmlSAX2AttributeInternal:
1060 * @ctx: the user data (XML parser context)
1061 * @fullname: The attribute name, including namespace prefix
1062 * @value: The attribute value
1063 * @prefix: the prefix on the element node
1064 *
1065 * Handle an attribute that has been read by the parser.
1066 * The default handling is to convert the attribute into an
1067 * DOM subtree and past it in a new xmlAttr element added to
1068 * the element.
1069 */
1070 static void
xmlSAX2AttributeInternal(void * ctx,const xmlChar * fullname,const xmlChar * value,const xmlChar * prefix ATTRIBUTE_UNUSED)1071 xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname,
1072 const xmlChar *value, const xmlChar *prefix ATTRIBUTE_UNUSED)
1073 {
1074 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1075 xmlAttrPtr ret;
1076 xmlChar *name;
1077 xmlChar *ns;
1078 xmlChar *nval;
1079 xmlNsPtr namespace;
1080
1081 if (ctxt->html) {
1082 name = xmlStrdup(fullname);
1083 ns = NULL;
1084 namespace = NULL;
1085 } else {
1086 /*
1087 * Split the full name into a namespace prefix and the tag name
1088 */
1089 name = xmlSplitQName(ctxt, fullname, &ns);
1090 if ((name != NULL) && (name[0] == 0)) {
1091 if (xmlStrEqual(ns, BAD_CAST "xmlns")) {
1092 xmlNsErrMsg(ctxt, XML_ERR_NS_DECL_ERROR,
1093 "invalid namespace declaration '%s'\n",
1094 fullname, NULL);
1095 } else {
1096 xmlNsWarnMsg(ctxt, XML_WAR_NS_COLUMN,
1097 "Avoid attribute ending with ':' like '%s'\n",
1098 fullname, NULL);
1099 }
1100 if (ns != NULL)
1101 xmlFree(ns);
1102 ns = NULL;
1103 xmlFree(name);
1104 name = xmlStrdup(fullname);
1105 }
1106 }
1107 if (name == NULL) {
1108 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
1109 if (ns != NULL)
1110 xmlFree(ns);
1111 return;
1112 }
1113
1114 #ifdef LIBXML_HTML_ENABLED
1115 if ((ctxt->html) &&
1116 (value == NULL) && (htmlIsBooleanAttr(fullname))) {
1117 nval = xmlStrdup(fullname);
1118 value = (const xmlChar *) nval;
1119 } else
1120 #endif
1121 {
1122 #ifdef LIBXML_VALID_ENABLED
1123 /*
1124 * Do the last stage of the attribute normalization
1125 * Needed for HTML too:
1126 * http://www.w3.org/TR/html4/types.html#h-6.2
1127 */
1128 ctxt->vctxt.valid = 1;
1129 nval = xmlValidCtxtNormalizeAttributeValue(&ctxt->vctxt,
1130 ctxt->myDoc, ctxt->node,
1131 fullname, value);
1132 if (ctxt->vctxt.valid != 1) {
1133 ctxt->valid = 0;
1134 }
1135 if (nval != NULL)
1136 value = nval;
1137 #else
1138 nval = NULL;
1139 #endif /* LIBXML_VALID_ENABLED */
1140 }
1141
1142 /*
1143 * Check whether it's a namespace definition
1144 */
1145 if ((!ctxt->html) && (ns == NULL) &&
1146 (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
1147 (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
1148 xmlNsPtr nsret;
1149 xmlChar *val;
1150
1151 /* Avoid unused variable warning if features are disabled. */
1152 (void) nsret;
1153
1154 if (!ctxt->replaceEntities) {
1155 ctxt->depth++;
1156 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
1157 0,0,0);
1158 ctxt->depth--;
1159 if (val == NULL) {
1160 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
1161 if (name != NULL)
1162 xmlFree(name);
1163 if (nval != NULL)
1164 xmlFree(nval);
1165 return;
1166 }
1167 } else {
1168 val = (xmlChar *) value;
1169 }
1170
1171 if (val[0] != 0) {
1172 xmlURIPtr uri;
1173
1174 uri = xmlParseURI((const char *)val);
1175 if (uri == NULL) {
1176 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1177 ctxt->sax->warning(ctxt->userData,
1178 "xmlns: %s not a valid URI\n", val);
1179 } else {
1180 if (uri->scheme == NULL) {
1181 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1182 ctxt->sax->warning(ctxt->userData,
1183 "xmlns: URI %s is not absolute\n", val);
1184 }
1185 xmlFreeURI(uri);
1186 }
1187 }
1188
1189 /* a default namespace definition */
1190 nsret = xmlNewNs(ctxt->node, val, NULL);
1191
1192 #ifdef LIBXML_VALID_ENABLED
1193 /*
1194 * Validate also for namespace decls, they are attributes from
1195 * an XML-1.0 perspective
1196 */
1197 if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
1198 ctxt->myDoc && ctxt->myDoc->intSubset)
1199 ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
1200 ctxt->node, prefix, nsret, val);
1201 #endif /* LIBXML_VALID_ENABLED */
1202 if (name != NULL)
1203 xmlFree(name);
1204 if (nval != NULL)
1205 xmlFree(nval);
1206 if (val != value)
1207 xmlFree(val);
1208 return;
1209 }
1210 if ((!ctxt->html) &&
1211 (ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
1212 (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
1213 xmlNsPtr nsret;
1214 xmlChar *val;
1215
1216 /* Avoid unused variable warning if features are disabled. */
1217 (void) nsret;
1218
1219 if (!ctxt->replaceEntities) {
1220 ctxt->depth++;
1221 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
1222 0,0,0);
1223 ctxt->depth--;
1224 if (val == NULL) {
1225 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
1226 xmlFree(ns);
1227 if (name != NULL)
1228 xmlFree(name);
1229 if (nval != NULL)
1230 xmlFree(nval);
1231 return;
1232 }
1233 } else {
1234 val = (xmlChar *) value;
1235 }
1236
1237 if (val[0] == 0) {
1238 xmlNsErrMsg(ctxt, XML_NS_ERR_EMPTY,
1239 "Empty namespace name for prefix %s\n", name, NULL);
1240 }
1241 if ((ctxt->pedantic != 0) && (val[0] != 0)) {
1242 xmlURIPtr uri;
1243
1244 uri = xmlParseURI((const char *)val);
1245 if (uri == NULL) {
1246 xmlNsWarnMsg(ctxt, XML_WAR_NS_URI,
1247 "xmlns:%s: %s not a valid URI\n", name, value);
1248 } else {
1249 if (uri->scheme == NULL) {
1250 xmlNsWarnMsg(ctxt, XML_WAR_NS_URI_RELATIVE,
1251 "xmlns:%s: URI %s is not absolute\n", name, value);
1252 }
1253 xmlFreeURI(uri);
1254 }
1255 }
1256
1257 /* a standard namespace definition */
1258 nsret = xmlNewNs(ctxt->node, val, name);
1259 xmlFree(ns);
1260 #ifdef LIBXML_VALID_ENABLED
1261 /*
1262 * Validate also for namespace decls, they are attributes from
1263 * an XML-1.0 perspective
1264 */
1265 if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
1266 ctxt->myDoc && ctxt->myDoc->intSubset)
1267 ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
1268 ctxt->node, prefix, nsret, value);
1269 #endif /* LIBXML_VALID_ENABLED */
1270 if (name != NULL)
1271 xmlFree(name);
1272 if (nval != NULL)
1273 xmlFree(nval);
1274 if (val != value)
1275 xmlFree(val);
1276 return;
1277 }
1278
1279 if (ns != NULL) {
1280 namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
1281
1282 if (namespace == NULL) {
1283 xmlNsErrMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
1284 "Namespace prefix %s of attribute %s is not defined\n",
1285 ns, name);
1286 } else {
1287 xmlAttrPtr prop;
1288
1289 prop = ctxt->node->properties;
1290 while (prop != NULL) {
1291 if (prop->ns != NULL) {
1292 if ((xmlStrEqual(name, prop->name)) &&
1293 ((namespace == prop->ns) ||
1294 (xmlStrEqual(namespace->href, prop->ns->href)))) {
1295 xmlNsErrMsg(ctxt, XML_ERR_ATTRIBUTE_REDEFINED,
1296 "Attribute %s in %s redefined\n",
1297 name, namespace->href);
1298 ctxt->wellFormed = 0;
1299 if (ctxt->recovery == 0) ctxt->disableSAX = 1;
1300 if (name != NULL)
1301 xmlFree(name);
1302 goto error;
1303 }
1304 }
1305 prop = prop->next;
1306 }
1307 }
1308 } else {
1309 namespace = NULL;
1310 }
1311
1312 /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */
1313 ret = xmlNewNsPropEatName(ctxt->node, namespace, name, NULL);
1314
1315 if (ret != NULL) {
1316 if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
1317 xmlNodePtr tmp;
1318
1319 ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
1320 tmp = ret->children;
1321 while (tmp != NULL) {
1322 tmp->parent = (xmlNodePtr) ret;
1323 if (tmp->next == NULL)
1324 ret->last = tmp;
1325 tmp = tmp->next;
1326 }
1327 } else if (value != NULL) {
1328 ret->children = xmlNewDocText(ctxt->myDoc, value);
1329 ret->last = ret->children;
1330 if (ret->children != NULL)
1331 ret->children->parent = (xmlNodePtr) ret;
1332 }
1333 }
1334
1335 #ifdef LIBXML_VALID_ENABLED
1336 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
1337 ctxt->myDoc && ctxt->myDoc->intSubset) {
1338
1339 /*
1340 * If we don't substitute entities, the validation should be
1341 * done on a value with replaced entities anyway.
1342 */
1343 if (!ctxt->replaceEntities) {
1344 xmlChar *val;
1345
1346 ctxt->depth++;
1347 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
1348 0,0,0);
1349 ctxt->depth--;
1350
1351 if (val == NULL)
1352 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1353 ctxt->myDoc, ctxt->node, ret, value);
1354 else {
1355 xmlChar *nvalnorm;
1356
1357 /*
1358 * Do the last stage of the attribute normalization
1359 * It need to be done twice ... it's an extra burden related
1360 * to the ability to keep xmlSAX2References in attributes
1361 */
1362 nvalnorm = xmlValidNormalizeAttributeValue(ctxt->myDoc,
1363 ctxt->node, fullname, val);
1364 if (nvalnorm != NULL) {
1365 xmlFree(val);
1366 val = nvalnorm;
1367 }
1368
1369 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1370 ctxt->myDoc, ctxt->node, ret, val);
1371 xmlFree(val);
1372 }
1373 } else {
1374 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
1375 ctxt->node, ret, value);
1376 }
1377 } else
1378 #endif /* LIBXML_VALID_ENABLED */
1379 if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) &&
1380 (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
1381 ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) &&
1382 /* Don't create IDs containing entity references */
1383 (ret->children != NULL) &&
1384 (ret->children->type == XML_TEXT_NODE) &&
1385 (ret->children->next == NULL)) {
1386 xmlChar *content = ret->children->content;
1387 /*
1388 * when validating, the ID registration is done at the attribute
1389 * validation level. Otherwise we have to do specific handling here.
1390 */
1391 if (xmlStrEqual(fullname, BAD_CAST "xml:id")) {
1392 /*
1393 * Add the xml:id value
1394 *
1395 * Open issue: normalization of the value.
1396 */
1397 if (xmlValidateNCName(content, 1) != 0) {
1398 xmlErrValid(ctxt, XML_DTD_XMLID_VALUE,
1399 "xml:id : attribute value %s is not an NCName\n",
1400 (const char *) content, NULL);
1401 }
1402 xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
1403 } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
1404 xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
1405 else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
1406 xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret);
1407 }
1408
1409 error:
1410 if (nval != NULL)
1411 xmlFree(nval);
1412 if (ns != NULL)
1413 xmlFree(ns);
1414 }
1415
1416 /*
1417 * xmlCheckDefaultedAttributes:
1418 *
1419 * Check defaulted attributes from the DTD
1420 */
1421 static void
xmlCheckDefaultedAttributes(xmlParserCtxtPtr ctxt,const xmlChar * name,const xmlChar * prefix,const xmlChar ** atts)1422 xmlCheckDefaultedAttributes(xmlParserCtxtPtr ctxt, const xmlChar *name,
1423 const xmlChar *prefix, const xmlChar **atts) {
1424 xmlElementPtr elemDecl;
1425 const xmlChar *att;
1426 int internal = 1;
1427 int i;
1428
1429 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->intSubset, name, prefix);
1430 if (elemDecl == NULL) {
1431 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset, name, prefix);
1432 internal = 0;
1433 }
1434
1435 process_external_subset:
1436
1437 if (elemDecl != NULL) {
1438 xmlAttributePtr attr = elemDecl->attributes;
1439 /*
1440 * Check against defaulted attributes from the external subset
1441 * if the document is stamped as standalone
1442 */
1443 if ((ctxt->myDoc->standalone == 1) &&
1444 (ctxt->myDoc->extSubset != NULL) &&
1445 (ctxt->validate)) {
1446 while (attr != NULL) {
1447 if ((attr->defaultValue != NULL) &&
1448 (xmlGetDtdQAttrDesc(ctxt->myDoc->extSubset,
1449 attr->elem, attr->name,
1450 attr->prefix) == attr) &&
1451 (xmlGetDtdQAttrDesc(ctxt->myDoc->intSubset,
1452 attr->elem, attr->name,
1453 attr->prefix) == NULL)) {
1454 xmlChar *fulln;
1455
1456 if (attr->prefix != NULL) {
1457 fulln = xmlStrdup(attr->prefix);
1458 fulln = xmlStrcat(fulln, BAD_CAST ":");
1459 fulln = xmlStrcat(fulln, attr->name);
1460 } else {
1461 fulln = xmlStrdup(attr->name);
1462 }
1463 if (fulln == NULL) {
1464 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
1465 break;
1466 }
1467
1468 /*
1469 * Check that the attribute is not declared in the
1470 * serialization
1471 */
1472 att = NULL;
1473 if (atts != NULL) {
1474 i = 0;
1475 att = atts[i];
1476 while (att != NULL) {
1477 if (xmlStrEqual(att, fulln))
1478 break;
1479 i += 2;
1480 att = atts[i];
1481 }
1482 }
1483 if (att == NULL) {
1484 xmlErrValid(ctxt, XML_DTD_STANDALONE_DEFAULTED,
1485 "standalone: attribute %s on %s defaulted from external subset\n",
1486 (const char *)fulln,
1487 (const char *)attr->elem);
1488 }
1489 xmlFree(fulln);
1490 }
1491 attr = attr->nexth;
1492 }
1493 }
1494
1495 /*
1496 * Actually insert defaulted values when needed
1497 */
1498 attr = elemDecl->attributes;
1499 while (attr != NULL) {
1500 /*
1501 * Make sure that attributes redefinition occurring in the
1502 * internal subset are not overridden by definitions in the
1503 * external subset.
1504 */
1505 if (attr->defaultValue != NULL) {
1506 /*
1507 * the element should be instantiated in the tree if:
1508 * - this is a namespace prefix
1509 * - the user required for completion in the tree
1510 * like XSLT
1511 * - there isn't already an attribute definition
1512 * in the internal subset overriding it.
1513 */
1514 if (((attr->prefix != NULL) &&
1515 (xmlStrEqual(attr->prefix, BAD_CAST "xmlns"))) ||
1516 ((attr->prefix == NULL) &&
1517 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) ||
1518 (ctxt->loadsubset & XML_COMPLETE_ATTRS)) {
1519 xmlAttributePtr tst;
1520
1521 tst = xmlGetDtdQAttrDesc(ctxt->myDoc->intSubset,
1522 attr->elem, attr->name,
1523 attr->prefix);
1524 if ((tst == attr) || (tst == NULL)) {
1525 xmlChar fn[50];
1526 xmlChar *fulln;
1527
1528 fulln = xmlBuildQName(attr->name, attr->prefix, fn, 50);
1529 if (fulln == NULL) {
1530 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
1531 return;
1532 }
1533
1534 /*
1535 * Check that the attribute is not declared in the
1536 * serialization
1537 */
1538 att = NULL;
1539 if (atts != NULL) {
1540 i = 0;
1541 att = atts[i];
1542 while (att != NULL) {
1543 if (xmlStrEqual(att, fulln))
1544 break;
1545 i += 2;
1546 att = atts[i];
1547 }
1548 }
1549 if (att == NULL) {
1550 xmlSAX2AttributeInternal(ctxt, fulln,
1551 attr->defaultValue, prefix);
1552 }
1553 if ((fulln != fn) && (fulln != attr->name))
1554 xmlFree(fulln);
1555 }
1556 }
1557 }
1558 attr = attr->nexth;
1559 }
1560 if (internal == 1) {
1561 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset,
1562 name, prefix);
1563 internal = 0;
1564 goto process_external_subset;
1565 }
1566 }
1567 }
1568
1569 /**
1570 * xmlSAX2StartElement:
1571 * @ctx: the user data (XML parser context)
1572 * @fullname: The element name, including namespace prefix
1573 * @atts: An array of name/value attributes pairs, NULL terminated
1574 *
1575 * called when an opening tag has been processed.
1576 */
1577 void
xmlSAX2StartElement(void * ctx,const xmlChar * fullname,const xmlChar ** atts)1578 xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
1579 {
1580 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1581 xmlNodePtr ret;
1582 xmlNodePtr parent;
1583 xmlNsPtr ns;
1584 xmlChar *name;
1585 xmlChar *prefix;
1586 const xmlChar *att;
1587 const xmlChar *value;
1588 int i;
1589
1590 if ((ctx == NULL) || (fullname == NULL) || (ctxt->myDoc == NULL)) return;
1591 parent = ctxt->node;
1592 #ifdef DEBUG_SAX
1593 xmlGenericError(xmlGenericErrorContext,
1594 "SAX.xmlSAX2StartElement(%s)\n", fullname);
1595 #endif
1596
1597 /*
1598 * First check on validity:
1599 */
1600 if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
1601 ((ctxt->myDoc->intSubset == NULL) ||
1602 ((ctxt->myDoc->intSubset->notations == NULL) &&
1603 (ctxt->myDoc->intSubset->elements == NULL) &&
1604 (ctxt->myDoc->intSubset->attributes == NULL) &&
1605 (ctxt->myDoc->intSubset->entities == NULL)))) {
1606 xmlErrValid(ctxt, XML_ERR_NO_DTD,
1607 "Validation failed: no DTD found !", NULL, NULL);
1608 ctxt->validate = 0;
1609 }
1610
1611
1612 /*
1613 * Split the full name into a namespace prefix and the tag name
1614 */
1615 name = xmlSplitQName(ctxt, fullname, &prefix);
1616
1617
1618 /*
1619 * Note : the namespace resolution is deferred until the end of the
1620 * attributes parsing, since local namespace can be defined as
1621 * an attribute at this level.
1622 */
1623 ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL);
1624 if (ret == NULL) {
1625 if (prefix != NULL)
1626 xmlFree(prefix);
1627 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
1628 return;
1629 }
1630 if (ctxt->myDoc->children == NULL) {
1631 #ifdef DEBUG_SAX_TREE
1632 xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
1633 #endif
1634 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1635 } else if (parent == NULL) {
1636 parent = ctxt->myDoc->children;
1637 }
1638 ctxt->nodemem = -1;
1639 if (ctxt->linenumbers) {
1640 if (ctxt->input != NULL) {
1641 if (ctxt->input->line < USHRT_MAX)
1642 ret->line = (unsigned short) ctxt->input->line;
1643 else
1644 ret->line = USHRT_MAX;
1645 }
1646 }
1647
1648 /*
1649 * We are parsing a new node.
1650 */
1651 #ifdef DEBUG_SAX_TREE
1652 xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name);
1653 #endif
1654 if (nodePush(ctxt, ret) < 0) {
1655 xmlUnlinkNode(ret);
1656 xmlFreeNode(ret);
1657 if (prefix != NULL)
1658 xmlFree(prefix);
1659 return;
1660 }
1661
1662 /*
1663 * Link the child element
1664 */
1665 if (parent != NULL) {
1666 if (parent->type == XML_ELEMENT_NODE) {
1667 #ifdef DEBUG_SAX_TREE
1668 xmlGenericError(xmlGenericErrorContext,
1669 "adding child %s to %s\n", name, parent->name);
1670 #endif
1671 xmlAddChild(parent, ret);
1672 } else {
1673 #ifdef DEBUG_SAX_TREE
1674 xmlGenericError(xmlGenericErrorContext,
1675 "adding sibling %s to ", name);
1676 xmlDebugDumpOneNode(stderr, parent, 0);
1677 #endif
1678 xmlAddSibling(parent, ret);
1679 }
1680 }
1681
1682 if (!ctxt->html) {
1683 /*
1684 * Insert all the defaulted attributes from the DTD especially
1685 * namespaces
1686 */
1687 if ((ctxt->myDoc->intSubset != NULL) ||
1688 (ctxt->myDoc->extSubset != NULL)) {
1689 xmlCheckDefaultedAttributes(ctxt, name, prefix, atts);
1690 }
1691
1692 /*
1693 * process all the attributes whose name start with "xmlns"
1694 */
1695 if (atts != NULL) {
1696 i = 0;
1697 att = atts[i++];
1698 value = atts[i++];
1699 while ((att != NULL) && (value != NULL)) {
1700 if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l') &&
1701 (att[3] == 'n') && (att[4] == 's'))
1702 xmlSAX2AttributeInternal(ctxt, att, value, prefix);
1703
1704 att = atts[i++];
1705 value = atts[i++];
1706 }
1707 }
1708
1709 /*
1710 * Search the namespace, note that since the attributes have been
1711 * processed, the local namespaces are available.
1712 */
1713 ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
1714 if ((ns == NULL) && (parent != NULL))
1715 ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
1716 if ((prefix != NULL) && (ns == NULL)) {
1717 ns = xmlNewNs(ret, NULL, prefix);
1718 xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
1719 "Namespace prefix %s is not defined\n",
1720 prefix, NULL);
1721 }
1722
1723 /*
1724 * set the namespace node, making sure that if the default namespace
1725 * is unbound on a parent we simply keep it NULL
1726 */
1727 if ((ns != NULL) && (ns->href != NULL) &&
1728 ((ns->href[0] != 0) || (ns->prefix != NULL)))
1729 xmlSetNs(ret, ns);
1730 }
1731
1732 /*
1733 * process all the other attributes
1734 */
1735 if (atts != NULL) {
1736 i = 0;
1737 att = atts[i++];
1738 value = atts[i++];
1739 if (ctxt->html) {
1740 while (att != NULL) {
1741 xmlSAX2AttributeInternal(ctxt, att, value, NULL);
1742 att = atts[i++];
1743 value = atts[i++];
1744 }
1745 } else {
1746 while ((att != NULL) && (value != NULL)) {
1747 if ((att[0] != 'x') || (att[1] != 'm') || (att[2] != 'l') ||
1748 (att[3] != 'n') || (att[4] != 's'))
1749 xmlSAX2AttributeInternal(ctxt, att, value, NULL);
1750
1751 /*
1752 * Next ones
1753 */
1754 att = atts[i++];
1755 value = atts[i++];
1756 }
1757 }
1758 }
1759
1760 #ifdef LIBXML_VALID_ENABLED
1761 /*
1762 * If it's the Document root, finish the DTD validation and
1763 * check the document root element for validity
1764 */
1765 if ((ctxt->validate) &&
1766 ((ctxt->vctxt.flags & XML_VCTXT_DTD_VALIDATED) == 0)) {
1767 int chk;
1768
1769 chk = xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
1770 if (chk <= 0)
1771 ctxt->valid = 0;
1772 if (chk < 0)
1773 ctxt->wellFormed = 0;
1774 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
1775 ctxt->vctxt.flags |= XML_VCTXT_DTD_VALIDATED;
1776 }
1777 #endif /* LIBXML_VALID_ENABLED */
1778
1779 if (prefix != NULL)
1780 xmlFree(prefix);
1781
1782 }
1783
1784 /**
1785 * xmlSAX2EndElement:
1786 * @ctx: the user data (XML parser context)
1787 * @name: The element name
1788 *
1789 * called when the end of an element has been detected.
1790 */
1791 void
xmlSAX2EndElement(void * ctx,const xmlChar * name ATTRIBUTE_UNUSED)1792 xmlSAX2EndElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED)
1793 {
1794 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1795 xmlNodePtr cur;
1796
1797 if (ctx == NULL) return;
1798 cur = ctxt->node;
1799 #ifdef DEBUG_SAX
1800 if (name == NULL)
1801 xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2EndElement(NULL)\n");
1802 else
1803 xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2EndElement(%s)\n", name);
1804 #endif
1805
1806 /* Capture end position and add node */
1807 if (cur != NULL && ctxt->record_info) {
1808 ctxt->nodeInfo->end_pos = ctxt->input->cur - ctxt->input->base;
1809 ctxt->nodeInfo->end_line = ctxt->input->line;
1810 ctxt->nodeInfo->node = cur;
1811 xmlParserAddNodeInfo(ctxt, ctxt->nodeInfo);
1812 }
1813 ctxt->nodemem = -1;
1814
1815 #ifdef LIBXML_VALID_ENABLED
1816 if (ctxt->validate && ctxt->wellFormed &&
1817 ctxt->myDoc && ctxt->myDoc->intSubset)
1818 ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc,
1819 cur);
1820 #endif /* LIBXML_VALID_ENABLED */
1821
1822
1823 /*
1824 * end of parsing of this node.
1825 */
1826 #ifdef DEBUG_SAX_TREE
1827 xmlGenericError(xmlGenericErrorContext, "popping(%s)\n", cur->name);
1828 #endif
1829 nodePop(ctxt);
1830 }
1831 #endif /* LIBXML_SAX1_ENABLED || LIBXML_HTML_ENABLED || LIBXML_LEGACY_ENABLED */
1832
1833 /*
1834 * xmlSAX2TextNode:
1835 * @ctxt: the parser context
1836 * @str: the input string
1837 * @len: the string length
1838 *
1839 * Callback for a text node
1840 *
1841 * Returns the newly allocated string or NULL if not needed or error
1842 */
1843 static xmlNodePtr
xmlSAX2TextNode(xmlParserCtxtPtr ctxt,const xmlChar * str,int len)1844 xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
1845 xmlNodePtr ret;
1846 const xmlChar *intern = NULL;
1847
1848 /*
1849 * Allocate
1850 */
1851 if (ctxt->freeElems != NULL) {
1852 ret = ctxt->freeElems;
1853 ctxt->freeElems = ret->next;
1854 ctxt->freeElemsNr--;
1855 } else {
1856 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1857 }
1858 if (ret == NULL) {
1859 xmlErrMemory(ctxt, "xmlSAX2Characters");
1860 return(NULL);
1861 }
1862 memset(ret, 0, sizeof(xmlNode));
1863 /*
1864 * intern the formatting blanks found between tags, or the
1865 * very short strings
1866 */
1867 if (ctxt->dictNames) {
1868 xmlChar cur = str[len];
1869
1870 if ((len < (int) (2 * sizeof(void *))) &&
1871 (ctxt->options & XML_PARSE_COMPACT)) {
1872 /* store the string in the node overriding properties and nsDef */
1873 xmlChar *tmp = (xmlChar *) &(ret->properties);
1874 memcpy(tmp, str, len);
1875 tmp[len] = 0;
1876 intern = tmp;
1877 } else if ((len <= 3) && ((cur == '"') || (cur == '\'') ||
1878 ((cur == '<') && (str[len + 1] != '!')))) {
1879 intern = xmlDictLookup(ctxt->dict, str, len);
1880 } else if (IS_BLANK_CH(*str) && (len < 60) && (cur == '<') &&
1881 (str[len + 1] != '!')) {
1882 int i;
1883
1884 for (i = 1;i < len;i++) {
1885 if (!IS_BLANK_CH(str[i])) goto skip;
1886 }
1887 intern = xmlDictLookup(ctxt->dict, str, len);
1888 }
1889 }
1890 skip:
1891 ret->type = XML_TEXT_NODE;
1892
1893 ret->name = xmlStringText;
1894 if (intern == NULL) {
1895 ret->content = xmlStrndup(str, len);
1896 if (ret->content == NULL) {
1897 xmlSAX2ErrMemory(ctxt, "xmlSAX2TextNode");
1898 xmlFree(ret);
1899 return(NULL);
1900 }
1901 } else
1902 ret->content = (xmlChar *) intern;
1903
1904 if (ctxt->linenumbers) {
1905 if (ctxt->input != NULL) {
1906 if (ctxt->input->line < USHRT_MAX)
1907 ret->line = (unsigned short) ctxt->input->line;
1908 else {
1909 ret->line = USHRT_MAX;
1910 if (ctxt->options & XML_PARSE_BIG_LINES)
1911 ret->psvi = (void *) (ptrdiff_t) ctxt->input->line;
1912 }
1913 }
1914 }
1915
1916 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1917 xmlRegisterNodeDefaultValue(ret);
1918 return(ret);
1919 }
1920
1921 #ifdef LIBXML_VALID_ENABLED
1922 /*
1923 * xmlSAX2DecodeAttrEntities:
1924 * @ctxt: the parser context
1925 * @str: the input string
1926 * @len: the string length
1927 *
1928 * Remove the entities from an attribute value
1929 *
1930 * Returns the newly allocated string or NULL if not needed or error
1931 */
1932 static xmlChar *
xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt,const xmlChar * str,const xmlChar * end)1933 xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str,
1934 const xmlChar *end) {
1935 const xmlChar *in;
1936 xmlChar *ret;
1937
1938 in = str;
1939 while (in < end)
1940 if (*in++ == '&')
1941 goto decode;
1942 return(NULL);
1943 decode:
1944 ctxt->depth++;
1945 ret = xmlStringLenDecodeEntities(ctxt, str, end - str,
1946 XML_SUBSTITUTE_REF, 0,0,0);
1947 ctxt->depth--;
1948 return(ret);
1949 }
1950 #endif /* LIBXML_VALID_ENABLED */
1951
1952 /**
1953 * xmlSAX2AttributeNs:
1954 * @ctx: the user data (XML parser context)
1955 * @localname: the local name of the attribute
1956 * @prefix: the attribute namespace prefix if available
1957 * @URI: the attribute namespace name if available
1958 * @value: Start of the attribute value
1959 * @valueend: end of the attribute value
1960 *
1961 * Handle an attribute that has been read by the parser.
1962 * The default handling is to convert the attribute into an
1963 * DOM subtree and past it in a new xmlAttr element added to
1964 * the element.
1965 */
1966 static void
xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt,const xmlChar * localname,const xmlChar * prefix,const xmlChar * value,const xmlChar * valueend)1967 xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt,
1968 const xmlChar * localname,
1969 const xmlChar * prefix,
1970 const xmlChar * value,
1971 const xmlChar * valueend)
1972 {
1973 xmlAttrPtr ret;
1974 xmlNsPtr namespace = NULL;
1975 xmlChar *dup = NULL;
1976
1977 /*
1978 * Note: if prefix == NULL, the attribute is not in the default namespace
1979 */
1980 if (prefix != NULL)
1981 namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix);
1982
1983 /*
1984 * allocate the node
1985 */
1986 if (ctxt->freeAttrs != NULL) {
1987 ret = ctxt->freeAttrs;
1988 ctxt->freeAttrs = ret->next;
1989 ctxt->freeAttrsNr--;
1990 memset(ret, 0, sizeof(xmlAttr));
1991 ret->type = XML_ATTRIBUTE_NODE;
1992
1993 ret->parent = ctxt->node;
1994 ret->doc = ctxt->myDoc;
1995 ret->ns = namespace;
1996
1997 if (ctxt->dictNames)
1998 ret->name = localname;
1999 else
2000 ret->name = xmlStrdup(localname);
2001
2002 /* link at the end to preserve order, TODO speed up with a last */
2003 if (ctxt->node->properties == NULL) {
2004 ctxt->node->properties = ret;
2005 } else {
2006 xmlAttrPtr prev = ctxt->node->properties;
2007
2008 while (prev->next != NULL) prev = prev->next;
2009 prev->next = ret;
2010 ret->prev = prev;
2011 }
2012
2013 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2014 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
2015 } else {
2016 if (ctxt->dictNames)
2017 ret = xmlNewNsPropEatName(ctxt->node, namespace,
2018 (xmlChar *) localname, NULL);
2019 else
2020 ret = xmlNewNsProp(ctxt->node, namespace, localname, NULL);
2021 if (ret == NULL) {
2022 xmlErrMemory(ctxt, "xmlSAX2AttributeNs");
2023 return;
2024 }
2025 }
2026
2027 if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
2028 xmlNodePtr tmp;
2029
2030 /*
2031 * We know that if there is an entity reference, then
2032 * the string has been dup'ed and terminates with 0
2033 * otherwise with ' or "
2034 */
2035 if (*valueend != 0) {
2036 tmp = xmlSAX2TextNode(ctxt, value, valueend - value);
2037 ret->children = tmp;
2038 ret->last = tmp;
2039 if (tmp != NULL) {
2040 tmp->doc = ret->doc;
2041 tmp->parent = (xmlNodePtr) ret;
2042 }
2043 } else {
2044 ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value,
2045 valueend - value);
2046 tmp = ret->children;
2047 while (tmp != NULL) {
2048 tmp->doc = ret->doc;
2049 tmp->parent = (xmlNodePtr) ret;
2050 if (tmp->next == NULL)
2051 ret->last = tmp;
2052 tmp = tmp->next;
2053 }
2054 }
2055 } else if (value != NULL) {
2056 xmlNodePtr tmp;
2057
2058 tmp = xmlSAX2TextNode(ctxt, value, valueend - value);
2059 ret->children = tmp;
2060 ret->last = tmp;
2061 if (tmp != NULL) {
2062 tmp->doc = ret->doc;
2063 tmp->parent = (xmlNodePtr) ret;
2064 }
2065 }
2066
2067 #ifdef LIBXML_VALID_ENABLED
2068 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
2069 ctxt->myDoc && ctxt->myDoc->intSubset) {
2070 /*
2071 * If we don't substitute entities, the validation should be
2072 * done on a value with replaced entities anyway.
2073 */
2074 if (!ctxt->replaceEntities) {
2075 dup = xmlSAX2DecodeAttrEntities(ctxt, value, valueend);
2076 if (dup == NULL) {
2077 if (*valueend == 0) {
2078 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
2079 ctxt->myDoc, ctxt->node, ret, value);
2080 } else {
2081 /*
2082 * That should already be normalized.
2083 * cheaper to finally allocate here than duplicate
2084 * entry points in the full validation code
2085 */
2086 dup = xmlStrndup(value, valueend - value);
2087
2088 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
2089 ctxt->myDoc, ctxt->node, ret, dup);
2090 }
2091 } else {
2092 /*
2093 * dup now contains a string of the flattened attribute
2094 * content with entities substituted. Check if we need to
2095 * apply an extra layer of normalization.
2096 * It need to be done twice ... it's an extra burden related
2097 * to the ability to keep references in attributes
2098 */
2099 if (ctxt->attsSpecial != NULL) {
2100 xmlChar *nvalnorm;
2101 xmlChar fn[50];
2102 xmlChar *fullname;
2103
2104 fullname = xmlBuildQName(localname, prefix, fn, 50);
2105 if (fullname != NULL) {
2106 ctxt->vctxt.valid = 1;
2107 nvalnorm = xmlValidCtxtNormalizeAttributeValue(
2108 &ctxt->vctxt, ctxt->myDoc,
2109 ctxt->node, fullname, dup);
2110 if (ctxt->vctxt.valid != 1)
2111 ctxt->valid = 0;
2112
2113 if ((fullname != fn) && (fullname != localname))
2114 xmlFree(fullname);
2115 if (nvalnorm != NULL) {
2116 xmlFree(dup);
2117 dup = nvalnorm;
2118 }
2119 }
2120 }
2121
2122 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
2123 ctxt->myDoc, ctxt->node, ret, dup);
2124 }
2125 } else {
2126 /*
2127 * if entities already have been substituted, then
2128 * the attribute as passed is already normalized
2129 */
2130 dup = xmlStrndup(value, valueend - value);
2131
2132 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
2133 ctxt->myDoc, ctxt->node, ret, dup);
2134 }
2135 } else
2136 #endif /* LIBXML_VALID_ENABLED */
2137 if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) &&
2138 (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
2139 ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) &&
2140 /* Don't create IDs containing entity references */
2141 (ret->children != NULL) &&
2142 (ret->children->type == XML_TEXT_NODE) &&
2143 (ret->children->next == NULL)) {
2144 xmlChar *content = ret->children->content;
2145 /*
2146 * when validating, the ID registration is done at the attribute
2147 * validation level. Otherwise we have to do specific handling here.
2148 */
2149 if ((prefix == ctxt->str_xml) &&
2150 (localname[0] == 'i') && (localname[1] == 'd') &&
2151 (localname[2] == 0)) {
2152 /*
2153 * Add the xml:id value
2154 *
2155 * Open issue: normalization of the value.
2156 */
2157 #if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
2158 #ifdef LIBXML_VALID_ENABLED
2159 if (xmlValidateNCName(content, 1) != 0) {
2160 xmlErrValid(ctxt, XML_DTD_XMLID_VALUE,
2161 "xml:id : attribute value %s is not an NCName\n",
2162 (const char *) content, NULL);
2163 }
2164 #endif
2165 #endif
2166 xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
2167 } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) {
2168 xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
2169 } else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) {
2170 xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret);
2171 }
2172 }
2173 if (dup != NULL)
2174 xmlFree(dup);
2175 }
2176
2177 /**
2178 * xmlSAX2StartElementNs:
2179 * @ctx: the user data (XML parser context)
2180 * @localname: the local name of the element
2181 * @prefix: the element namespace prefix if available
2182 * @URI: the element namespace name if available
2183 * @nb_namespaces: number of namespace definitions on that node
2184 * @namespaces: pointer to the array of prefix/URI pairs namespace definitions
2185 * @nb_attributes: the number of attributes on that node
2186 * @nb_defaulted: the number of defaulted attributes.
2187 * @attributes: pointer to the array of (localname/prefix/URI/value/end)
2188 * attribute values.
2189 *
2190 * SAX2 callback when an element start has been detected by the parser.
2191 * It provides the namespace information for the element, as well as
2192 * the new namespace declarations on the element.
2193 */
2194 void
xmlSAX2StartElementNs(void * ctx,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI,int nb_namespaces,const xmlChar ** namespaces,int nb_attributes,int nb_defaulted,const xmlChar ** attributes)2195 xmlSAX2StartElementNs(void *ctx,
2196 const xmlChar *localname,
2197 const xmlChar *prefix,
2198 const xmlChar *URI,
2199 int nb_namespaces,
2200 const xmlChar **namespaces,
2201 int nb_attributes,
2202 int nb_defaulted,
2203 const xmlChar **attributes)
2204 {
2205 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2206 xmlNodePtr ret;
2207 xmlNodePtr parent;
2208 xmlNsPtr last = NULL, ns;
2209 const xmlChar *uri, *pref;
2210 xmlChar *lname = NULL;
2211 int i, j;
2212
2213 if (ctx == NULL) return;
2214 parent = ctxt->node;
2215 /*
2216 * First check on validity:
2217 */
2218 if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
2219 ((ctxt->myDoc->intSubset == NULL) ||
2220 ((ctxt->myDoc->intSubset->notations == NULL) &&
2221 (ctxt->myDoc->intSubset->elements == NULL) &&
2222 (ctxt->myDoc->intSubset->attributes == NULL) &&
2223 (ctxt->myDoc->intSubset->entities == NULL)))) {
2224 xmlErrValid(ctxt, XML_DTD_NO_DTD,
2225 "Validation failed: no DTD found !", NULL, NULL);
2226 ctxt->validate = 0;
2227 }
2228
2229 /*
2230 * Take care of the rare case of an undefined namespace prefix
2231 */
2232 if ((prefix != NULL) && (URI == NULL)) {
2233 if (ctxt->dictNames) {
2234 const xmlChar *fullname;
2235
2236 fullname = xmlDictQLookup(ctxt->dict, prefix, localname);
2237 if (fullname != NULL)
2238 localname = fullname;
2239 } else {
2240 lname = xmlBuildQName(localname, prefix, NULL, 0);
2241 }
2242 }
2243 /*
2244 * allocate the node
2245 */
2246 if (ctxt->freeElems != NULL) {
2247 ret = ctxt->freeElems;
2248 ctxt->freeElems = ret->next;
2249 ctxt->freeElemsNr--;
2250 memset(ret, 0, sizeof(xmlNode));
2251 ret->doc = ctxt->myDoc;
2252 ret->type = XML_ELEMENT_NODE;
2253
2254 if (ctxt->dictNames)
2255 ret->name = localname;
2256 else {
2257 if (lname == NULL)
2258 ret->name = xmlStrdup(localname);
2259 else
2260 ret->name = lname;
2261 if (ret->name == NULL) {
2262 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
2263 return;
2264 }
2265 }
2266 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2267 xmlRegisterNodeDefaultValue(ret);
2268 } else {
2269 if (ctxt->dictNames)
2270 ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL,
2271 (xmlChar *) localname, NULL);
2272 else if (lname == NULL)
2273 ret = xmlNewDocNode(ctxt->myDoc, NULL, localname, NULL);
2274 else
2275 ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL,
2276 (xmlChar *) lname, NULL);
2277 if (ret == NULL) {
2278 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
2279 return;
2280 }
2281 }
2282 if (ctxt->linenumbers) {
2283 if (ctxt->input != NULL) {
2284 if (ctxt->input->line < USHRT_MAX)
2285 ret->line = (unsigned short) ctxt->input->line;
2286 else
2287 ret->line = USHRT_MAX;
2288 }
2289 }
2290
2291 if (parent == NULL) {
2292 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
2293 }
2294 /*
2295 * Build the namespace list
2296 */
2297 for (i = 0,j = 0;j < nb_namespaces;j++) {
2298 pref = namespaces[i++];
2299 uri = namespaces[i++];
2300 ns = xmlNewNs(NULL, uri, pref);
2301 if (ns != NULL) {
2302 if (last == NULL) {
2303 ret->nsDef = last = ns;
2304 } else {
2305 last->next = ns;
2306 last = ns;
2307 }
2308 if ((URI != NULL) && (prefix == pref))
2309 ret->ns = ns;
2310 } else {
2311 /*
2312 * any out of memory error would already have been raised
2313 * but we can't be guaranteed it's the actual error due to the
2314 * API, best is to skip in this case
2315 */
2316 continue;
2317 }
2318 #ifdef LIBXML_VALID_ENABLED
2319 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
2320 ctxt->myDoc && ctxt->myDoc->intSubset) {
2321 ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
2322 ret, prefix, ns, uri);
2323 }
2324 #endif /* LIBXML_VALID_ENABLED */
2325 }
2326 ctxt->nodemem = -1;
2327
2328 /*
2329 * We are parsing a new node.
2330 */
2331 if (nodePush(ctxt, ret) < 0) {
2332 xmlUnlinkNode(ret);
2333 xmlFreeNode(ret);
2334 return;
2335 }
2336
2337 /*
2338 * Link the child element
2339 */
2340 if (parent != NULL) {
2341 if (parent->type == XML_ELEMENT_NODE) {
2342 xmlAddChild(parent, ret);
2343 } else {
2344 xmlAddSibling(parent, ret);
2345 }
2346 }
2347
2348 /*
2349 * Insert the defaulted attributes from the DTD only if requested:
2350 */
2351 if ((nb_defaulted != 0) &&
2352 ((ctxt->loadsubset & XML_COMPLETE_ATTRS) == 0))
2353 nb_attributes -= nb_defaulted;
2354
2355 /*
2356 * Search the namespace if it wasn't already found
2357 * Note that, if prefix is NULL, this searches for the default Ns
2358 */
2359 if ((URI != NULL) && (ret->ns == NULL)) {
2360 ret->ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
2361 if ((ret->ns == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
2362 ret->ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
2363 }
2364 if (ret->ns == NULL) {
2365 ns = xmlNewNs(ret, NULL, prefix);
2366 if (ns == NULL) {
2367
2368 xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
2369 return;
2370 }
2371 if (prefix != NULL)
2372 xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
2373 "Namespace prefix %s was not found\n",
2374 prefix, NULL);
2375 else
2376 xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
2377 "Namespace default prefix was not found\n",
2378 NULL, NULL);
2379 }
2380 }
2381
2382 /*
2383 * process all the other attributes
2384 */
2385 if (nb_attributes > 0) {
2386 for (j = 0,i = 0;i < nb_attributes;i++,j+=5) {
2387 /*
2388 * Handle the rare case of an undefined attribute prefix
2389 */
2390 if ((attributes[j+1] != NULL) && (attributes[j+2] == NULL)) {
2391 if (ctxt->dictNames) {
2392 const xmlChar *fullname;
2393
2394 fullname = xmlDictQLookup(ctxt->dict, attributes[j+1],
2395 attributes[j]);
2396 if (fullname != NULL) {
2397 xmlSAX2AttributeNs(ctxt, fullname, NULL,
2398 attributes[j+3], attributes[j+4]);
2399 continue;
2400 }
2401 } else {
2402 lname = xmlBuildQName(attributes[j], attributes[j+1],
2403 NULL, 0);
2404 if (lname != NULL) {
2405 xmlSAX2AttributeNs(ctxt, lname, NULL,
2406 attributes[j+3], attributes[j+4]);
2407 xmlFree(lname);
2408 continue;
2409 }
2410 }
2411 }
2412 xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1],
2413 attributes[j+3], attributes[j+4]);
2414 }
2415 }
2416
2417 #ifdef LIBXML_VALID_ENABLED
2418 /*
2419 * If it's the Document root, finish the DTD validation and
2420 * check the document root element for validity
2421 */
2422 if ((ctxt->validate) &&
2423 ((ctxt->vctxt.flags & XML_VCTXT_DTD_VALIDATED) == 0)) {
2424 int chk;
2425
2426 chk = xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
2427 if (chk <= 0)
2428 ctxt->valid = 0;
2429 if (chk < 0)
2430 ctxt->wellFormed = 0;
2431 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
2432 ctxt->vctxt.flags |= XML_VCTXT_DTD_VALIDATED;
2433 }
2434 #endif /* LIBXML_VALID_ENABLED */
2435 }
2436
2437 /**
2438 * xmlSAX2EndElementNs:
2439 * @ctx: the user data (XML parser context)
2440 * @localname: the local name of the element
2441 * @prefix: the element namespace prefix if available
2442 * @URI: the element namespace name if available
2443 *
2444 * SAX2 callback when an element end has been detected by the parser.
2445 * It provides the namespace information for the element.
2446 */
2447 void
xmlSAX2EndElementNs(void * ctx,const xmlChar * localname ATTRIBUTE_UNUSED,const xmlChar * prefix ATTRIBUTE_UNUSED,const xmlChar * URI ATTRIBUTE_UNUSED)2448 xmlSAX2EndElementNs(void *ctx,
2449 const xmlChar * localname ATTRIBUTE_UNUSED,
2450 const xmlChar * prefix ATTRIBUTE_UNUSED,
2451 const xmlChar * URI ATTRIBUTE_UNUSED)
2452 {
2453 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2454 xmlParserNodeInfo node_info;
2455 xmlNodePtr cur;
2456
2457 if (ctx == NULL) return;
2458 cur = ctxt->node;
2459 /* Capture end position and add node */
2460 if ((ctxt->record_info) && (cur != NULL)) {
2461 node_info.end_pos = ctxt->input->cur - ctxt->input->base;
2462 node_info.end_line = ctxt->input->line;
2463 node_info.node = cur;
2464 xmlParserAddNodeInfo(ctxt, &node_info);
2465 }
2466 ctxt->nodemem = -1;
2467
2468 #ifdef LIBXML_VALID_ENABLED
2469 if (ctxt->validate && ctxt->wellFormed &&
2470 ctxt->myDoc && ctxt->myDoc->intSubset)
2471 ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc, cur);
2472 #endif /* LIBXML_VALID_ENABLED */
2473
2474 /*
2475 * end of parsing of this node.
2476 */
2477 nodePop(ctxt);
2478 }
2479
2480 /**
2481 * xmlSAX2Reference:
2482 * @ctx: the user data (XML parser context)
2483 * @name: The entity name
2484 *
2485 * called when an entity xmlSAX2Reference is detected.
2486 */
2487 void
xmlSAX2Reference(void * ctx,const xmlChar * name)2488 xmlSAX2Reference(void *ctx, const xmlChar *name)
2489 {
2490 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2491 xmlNodePtr ret;
2492
2493 if (ctx == NULL) return;
2494 #ifdef DEBUG_SAX
2495 xmlGenericError(xmlGenericErrorContext,
2496 "SAX.xmlSAX2Reference(%s)\n", name);
2497 #endif
2498 if (name[0] == '#')
2499 ret = xmlNewCharRef(ctxt->myDoc, name);
2500 else
2501 ret = xmlNewReference(ctxt->myDoc, name);
2502 #ifdef DEBUG_SAX_TREE
2503 xmlGenericError(xmlGenericErrorContext,
2504 "add xmlSAX2Reference %s to %s \n", name, ctxt->node->name);
2505 #endif
2506 if (xmlAddChild(ctxt->node, ret) == NULL) {
2507 xmlFreeNode(ret);
2508 }
2509 }
2510
2511 /**
2512 * xmlSAX2Text:
2513 * @ctx: the user data (XML parser context)
2514 * @ch: a xmlChar string
2515 * @len: the number of xmlChar
2516 * @type: text or cdata
2517 *
2518 * Append characters.
2519 */
2520 static void
xmlSAX2Text(xmlParserCtxtPtr ctxt,const xmlChar * ch,int len,xmlElementType type)2521 xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len,
2522 xmlElementType type)
2523 {
2524 xmlNodePtr lastChild;
2525
2526 if (ctxt == NULL) return;
2527 #ifdef DEBUG_SAX
2528 xmlGenericError(xmlGenericErrorContext,
2529 "SAX.xmlSAX2Characters(%.30s, %d)\n", ch, len);
2530 #endif
2531 /*
2532 * Handle the data if any. If there is no child
2533 * add it as content, otherwise if the last child is text,
2534 * concatenate it, else create a new node of type text.
2535 */
2536
2537 if (ctxt->node == NULL) {
2538 #ifdef DEBUG_SAX_TREE
2539 xmlGenericError(xmlGenericErrorContext,
2540 "add chars: ctxt->node == NULL !\n");
2541 #endif
2542 return;
2543 }
2544 lastChild = ctxt->node->last;
2545 #ifdef DEBUG_SAX_TREE
2546 xmlGenericError(xmlGenericErrorContext,
2547 "add chars to %s \n", ctxt->node->name);
2548 #endif
2549
2550 /*
2551 * Here we needed an accelerator mechanism in case of very large
2552 * elements. Use an attribute in the structure !!!
2553 */
2554 if (lastChild == NULL) {
2555 if (type == XML_TEXT_NODE)
2556 lastChild = xmlSAX2TextNode(ctxt, ch, len);
2557 else
2558 lastChild = xmlNewCDataBlock(ctxt->myDoc, ch, len);
2559 if (lastChild != NULL) {
2560 ctxt->node->children = lastChild;
2561 ctxt->node->last = lastChild;
2562 lastChild->parent = ctxt->node;
2563 lastChild->doc = ctxt->node->doc;
2564 ctxt->nodelen = len;
2565 ctxt->nodemem = len + 1;
2566 } else {
2567 xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
2568 return;
2569 }
2570 } else {
2571 int coalesceText = (lastChild != NULL) &&
2572 (lastChild->type == type) &&
2573 ((type != XML_TEXT_NODE) ||
2574 (lastChild->name == xmlStringText));
2575 if ((coalesceText) && (ctxt->nodemem != 0)) {
2576 /*
2577 * The whole point of maintaining nodelen and nodemem,
2578 * xmlTextConcat is too costly, i.e. compute length,
2579 * reallocate a new buffer, move data, append ch. Here
2580 * We try to minimize realloc() uses and avoid copying
2581 * and recomputing length over and over.
2582 */
2583 if (lastChild->content == (xmlChar *)&(lastChild->properties)) {
2584 lastChild->content = xmlStrdup(lastChild->content);
2585 lastChild->properties = NULL;
2586 } else if ((ctxt->nodemem == ctxt->nodelen + 1) &&
2587 (xmlDictOwns(ctxt->dict, lastChild->content))) {
2588 lastChild->content = xmlStrdup(lastChild->content);
2589 }
2590 if (lastChild->content == NULL) {
2591 xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: xmlStrdup returned NULL");
2592 return;
2593 }
2594 if (ctxt->nodelen > INT_MAX - len) {
2595 xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters overflow prevented");
2596 return;
2597 }
2598 if ((ctxt->nodelen + len > XML_MAX_TEXT_LENGTH) &&
2599 ((ctxt->options & XML_PARSE_HUGE) == 0)) {
2600 xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: huge text node");
2601 return;
2602 }
2603 if (ctxt->nodelen + len >= ctxt->nodemem) {
2604 xmlChar *newbuf;
2605 int size;
2606
2607 size = ctxt->nodemem > INT_MAX - len ?
2608 INT_MAX :
2609 ctxt->nodemem + len;
2610 size = size > INT_MAX / 2 ? INT_MAX : size * 2;
2611 newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
2612 if (newbuf == NULL) {
2613 xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
2614 return;
2615 }
2616 ctxt->nodemem = size;
2617 lastChild->content = newbuf;
2618 }
2619 memcpy(&lastChild->content[ctxt->nodelen], ch, len);
2620 ctxt->nodelen += len;
2621 lastChild->content[ctxt->nodelen] = 0;
2622 } else if (coalesceText) {
2623 if (xmlTextConcat(lastChild, ch, len)) {
2624 xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
2625 }
2626 if (ctxt->node->children != NULL) {
2627 ctxt->nodelen = xmlStrlen(lastChild->content);
2628 ctxt->nodemem = ctxt->nodelen + 1;
2629 }
2630 } else {
2631 /* Mixed content, first time */
2632 if (type == XML_TEXT_NODE) {
2633 lastChild = xmlSAX2TextNode(ctxt, ch, len);
2634 lastChild->doc = ctxt->myDoc;
2635 } else
2636 lastChild = xmlNewCDataBlock(ctxt->myDoc, ch, len);
2637 if (lastChild != NULL) {
2638 xmlAddChild(ctxt->node, lastChild);
2639 if (ctxt->node->children != NULL) {
2640 ctxt->nodelen = len;
2641 ctxt->nodemem = len + 1;
2642 }
2643 }
2644 }
2645 }
2646 }
2647
2648 /**
2649 * xmlSAX2Characters:
2650 * @ctx: the user data (XML parser context)
2651 * @ch: a xmlChar string
2652 * @len: the number of xmlChar
2653 *
2654 * receiving some chars from the parser.
2655 */
2656 void
xmlSAX2Characters(void * ctx,const xmlChar * ch,int len)2657 xmlSAX2Characters(void *ctx, const xmlChar *ch, int len)
2658 {
2659 xmlSAX2Text((xmlParserCtxtPtr) ctx, ch, len, XML_TEXT_NODE);
2660 }
2661
2662 /**
2663 * xmlSAX2IgnorableWhitespace:
2664 * @ctx: the user data (XML parser context)
2665 * @ch: a xmlChar string
2666 * @len: the number of xmlChar
2667 *
2668 * receiving some ignorable whitespaces from the parser.
2669 * UNUSED: by default the DOM building will use xmlSAX2Characters
2670 */
2671 void
xmlSAX2IgnorableWhitespace(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch ATTRIBUTE_UNUSED,int len ATTRIBUTE_UNUSED)2672 xmlSAX2IgnorableWhitespace(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch ATTRIBUTE_UNUSED, int len ATTRIBUTE_UNUSED)
2673 {
2674 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
2675 #ifdef DEBUG_SAX
2676 xmlGenericError(xmlGenericErrorContext,
2677 "SAX.xmlSAX2IgnorableWhitespace(%.30s, %d)\n", ch, len);
2678 #endif
2679 }
2680
2681 /**
2682 * xmlSAX2ProcessingInstruction:
2683 * @ctx: the user data (XML parser context)
2684 * @target: the target name
2685 * @data: the PI data's
2686 *
2687 * A processing instruction has been parsed.
2688 */
2689 void
xmlSAX2ProcessingInstruction(void * ctx,const xmlChar * target,const xmlChar * data)2690 xmlSAX2ProcessingInstruction(void *ctx, const xmlChar *target,
2691 const xmlChar *data)
2692 {
2693 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2694 xmlNodePtr ret;
2695 xmlNodePtr parent;
2696
2697 if (ctx == NULL) return;
2698 parent = ctxt->node;
2699 #ifdef DEBUG_SAX
2700 xmlGenericError(xmlGenericErrorContext,
2701 "SAX.xmlSAX2ProcessingInstruction(%s, %s)\n", target, data);
2702 #endif
2703
2704 ret = xmlNewDocPI(ctxt->myDoc, target, data);
2705 if (ret == NULL) return;
2706
2707 if (ctxt->linenumbers) {
2708 if (ctxt->input != NULL) {
2709 if (ctxt->input->line < USHRT_MAX)
2710 ret->line = (unsigned short) ctxt->input->line;
2711 else
2712 ret->line = USHRT_MAX;
2713 }
2714 }
2715 if (ctxt->inSubset == 1) {
2716 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
2717 return;
2718 } else if (ctxt->inSubset == 2) {
2719 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
2720 return;
2721 }
2722 if (parent == NULL) {
2723 #ifdef DEBUG_SAX_TREE
2724 xmlGenericError(xmlGenericErrorContext,
2725 "Setting PI %s as root\n", target);
2726 #endif
2727 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
2728 return;
2729 }
2730 if (parent->type == XML_ELEMENT_NODE) {
2731 #ifdef DEBUG_SAX_TREE
2732 xmlGenericError(xmlGenericErrorContext,
2733 "adding PI %s child to %s\n", target, parent->name);
2734 #endif
2735 xmlAddChild(parent, ret);
2736 } else {
2737 #ifdef DEBUG_SAX_TREE
2738 xmlGenericError(xmlGenericErrorContext,
2739 "adding PI %s sibling to ", target);
2740 xmlDebugDumpOneNode(stderr, parent, 0);
2741 #endif
2742 xmlAddSibling(parent, ret);
2743 }
2744 }
2745
2746 /**
2747 * xmlSAX2Comment:
2748 * @ctx: the user data (XML parser context)
2749 * @value: the xmlSAX2Comment content
2750 *
2751 * A xmlSAX2Comment has been parsed.
2752 */
2753 void
xmlSAX2Comment(void * ctx,const xmlChar * value)2754 xmlSAX2Comment(void *ctx, const xmlChar *value)
2755 {
2756 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2757 xmlNodePtr ret;
2758 xmlNodePtr parent;
2759
2760 if (ctx == NULL) return;
2761 parent = ctxt->node;
2762 #ifdef DEBUG_SAX
2763 xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2Comment(%s)\n", value);
2764 #endif
2765 ret = xmlNewDocComment(ctxt->myDoc, value);
2766 if (ret == NULL) return;
2767 if (ctxt->linenumbers) {
2768 if (ctxt->input != NULL) {
2769 if (ctxt->input->line < USHRT_MAX)
2770 ret->line = (unsigned short) ctxt->input->line;
2771 else
2772 ret->line = USHRT_MAX;
2773 }
2774 }
2775
2776 if (ctxt->inSubset == 1) {
2777 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
2778 return;
2779 } else if (ctxt->inSubset == 2) {
2780 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
2781 return;
2782 }
2783 if (parent == NULL) {
2784 #ifdef DEBUG_SAX_TREE
2785 xmlGenericError(xmlGenericErrorContext,
2786 "Setting xmlSAX2Comment as root\n");
2787 #endif
2788 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
2789 return;
2790 }
2791 if (parent->type == XML_ELEMENT_NODE) {
2792 #ifdef DEBUG_SAX_TREE
2793 xmlGenericError(xmlGenericErrorContext,
2794 "adding xmlSAX2Comment child to %s\n", parent->name);
2795 #endif
2796 xmlAddChild(parent, ret);
2797 } else {
2798 #ifdef DEBUG_SAX_TREE
2799 xmlGenericError(xmlGenericErrorContext,
2800 "adding xmlSAX2Comment sibling to ");
2801 xmlDebugDumpOneNode(stderr, parent, 0);
2802 #endif
2803 xmlAddSibling(parent, ret);
2804 }
2805 }
2806
2807 /**
2808 * xmlSAX2CDataBlock:
2809 * @ctx: the user data (XML parser context)
2810 * @value: The pcdata content
2811 * @len: the block length
2812 *
2813 * called when a pcdata block has been parsed
2814 */
2815 void
xmlSAX2CDataBlock(void * ctx,const xmlChar * value,int len)2816 xmlSAX2CDataBlock(void *ctx, const xmlChar *value, int len)
2817 {
2818 xmlSAX2Text((xmlParserCtxtPtr) ctx, value, len, XML_CDATA_SECTION_NODE);
2819 }
2820
2821 static int xmlSAX2DefaultVersionValue = 2;
2822
2823 #ifdef LIBXML_SAX1_ENABLED
2824 /**
2825 * xmlSAXDefaultVersion:
2826 * @version: the version, 1 or 2
2827 *
2828 * Set the default version of SAX used globally by the library.
2829 * By default, during initialization the default is set to 2.
2830 * Note that it is generally a better coding style to use
2831 * xmlSAXVersion() to set up the version explicitly for a given
2832 * parsing context.
2833 *
2834 * Returns the previous value in case of success and -1 in case of error.
2835 */
2836 int
xmlSAXDefaultVersion(int version)2837 xmlSAXDefaultVersion(int version)
2838 {
2839 int ret = xmlSAX2DefaultVersionValue;
2840
2841 if ((version != 1) && (version != 2))
2842 return(-1);
2843 xmlSAX2DefaultVersionValue = version;
2844 return(ret);
2845 }
2846 #endif /* LIBXML_SAX1_ENABLED */
2847
2848 /**
2849 * xmlSAXVersion:
2850 * @hdlr: the SAX handler
2851 * @version: the version, 1 or 2
2852 *
2853 * Initialize the default XML SAX handler according to the version
2854 *
2855 * Returns 0 in case of success and -1 in case of error.
2856 */
2857 int
xmlSAXVersion(xmlSAXHandler * hdlr,int version)2858 xmlSAXVersion(xmlSAXHandler *hdlr, int version)
2859 {
2860 if (hdlr == NULL) return(-1);
2861 if (version == 2) {
2862 hdlr->startElement = NULL;
2863 hdlr->endElement = NULL;
2864 hdlr->startElementNs = xmlSAX2StartElementNs;
2865 hdlr->endElementNs = xmlSAX2EndElementNs;
2866 hdlr->serror = NULL;
2867 hdlr->initialized = XML_SAX2_MAGIC;
2868 #ifdef LIBXML_SAX1_ENABLED
2869 } else if (version == 1) {
2870 hdlr->startElement = xmlSAX2StartElement;
2871 hdlr->endElement = xmlSAX2EndElement;
2872 hdlr->initialized = 1;
2873 #endif /* LIBXML_SAX1_ENABLED */
2874 } else
2875 return(-1);
2876 hdlr->internalSubset = xmlSAX2InternalSubset;
2877 hdlr->externalSubset = xmlSAX2ExternalSubset;
2878 hdlr->isStandalone = xmlSAX2IsStandalone;
2879 hdlr->hasInternalSubset = xmlSAX2HasInternalSubset;
2880 hdlr->hasExternalSubset = xmlSAX2HasExternalSubset;
2881 hdlr->resolveEntity = xmlSAX2ResolveEntity;
2882 hdlr->getEntity = xmlSAX2GetEntity;
2883 hdlr->getParameterEntity = xmlSAX2GetParameterEntity;
2884 hdlr->entityDecl = xmlSAX2EntityDecl;
2885 hdlr->attributeDecl = xmlSAX2AttributeDecl;
2886 hdlr->elementDecl = xmlSAX2ElementDecl;
2887 hdlr->notationDecl = xmlSAX2NotationDecl;
2888 hdlr->unparsedEntityDecl = xmlSAX2UnparsedEntityDecl;
2889 hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator;
2890 hdlr->startDocument = xmlSAX2StartDocument;
2891 hdlr->endDocument = xmlSAX2EndDocument;
2892 hdlr->reference = xmlSAX2Reference;
2893 hdlr->characters = xmlSAX2Characters;
2894 hdlr->cdataBlock = xmlSAX2CDataBlock;
2895 hdlr->ignorableWhitespace = xmlSAX2Characters;
2896 hdlr->processingInstruction = xmlSAX2ProcessingInstruction;
2897 hdlr->comment = xmlSAX2Comment;
2898 hdlr->warning = xmlParserWarning;
2899 hdlr->error = xmlParserError;
2900 hdlr->fatalError = xmlParserError;
2901
2902 return(0);
2903 }
2904
2905 /**
2906 * xmlSAX2InitDefaultSAXHandler:
2907 * @hdlr: the SAX handler
2908 * @warning: flag if non-zero sets the handler warning procedure
2909 *
2910 * Initialize the default XML SAX2 handler
2911 */
2912 void
xmlSAX2InitDefaultSAXHandler(xmlSAXHandler * hdlr,int warning)2913 xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning)
2914 {
2915 if ((hdlr == NULL) || (hdlr->initialized != 0))
2916 return;
2917
2918 xmlSAXVersion(hdlr, xmlSAX2DefaultVersionValue);
2919 if (warning == 0)
2920 hdlr->warning = NULL;
2921 else
2922 hdlr->warning = xmlParserWarning;
2923 }
2924
2925 /**
2926 * xmlDefaultSAXHandlerInit:
2927 *
2928 * DEPRECATED: This function will be made private. Call xmlInitParser to
2929 * initialize the library.
2930 *
2931 * Initialize the default SAX2 handler
2932 */
2933 void
xmlDefaultSAXHandlerInit(void)2934 xmlDefaultSAXHandlerInit(void)
2935 {
2936 #ifdef LIBXML_SAX1_ENABLED
2937 xmlSAXVersion((xmlSAXHandlerPtr) &xmlDefaultSAXHandler, 1);
2938 #endif /* LIBXML_SAX1_ENABLED */
2939 }
2940
2941 #ifdef LIBXML_HTML_ENABLED
2942
2943 /**
2944 * xmlSAX2InitHtmlDefaultSAXHandler:
2945 * @hdlr: the SAX handler
2946 *
2947 * Initialize the default HTML SAX2 handler
2948 */
2949 void
xmlSAX2InitHtmlDefaultSAXHandler(xmlSAXHandler * hdlr)2950 xmlSAX2InitHtmlDefaultSAXHandler(xmlSAXHandler *hdlr)
2951 {
2952 if ((hdlr == NULL) || (hdlr->initialized != 0))
2953 return;
2954
2955 hdlr->internalSubset = xmlSAX2InternalSubset;
2956 hdlr->externalSubset = NULL;
2957 hdlr->isStandalone = NULL;
2958 hdlr->hasInternalSubset = NULL;
2959 hdlr->hasExternalSubset = NULL;
2960 hdlr->resolveEntity = NULL;
2961 hdlr->getEntity = xmlSAX2GetEntity;
2962 hdlr->getParameterEntity = NULL;
2963 hdlr->entityDecl = NULL;
2964 hdlr->attributeDecl = NULL;
2965 hdlr->elementDecl = NULL;
2966 hdlr->notationDecl = NULL;
2967 hdlr->unparsedEntityDecl = NULL;
2968 hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator;
2969 hdlr->startDocument = xmlSAX2StartDocument;
2970 hdlr->endDocument = xmlSAX2EndDocument;
2971 hdlr->startElement = xmlSAX2StartElement;
2972 hdlr->endElement = xmlSAX2EndElement;
2973 hdlr->reference = NULL;
2974 hdlr->characters = xmlSAX2Characters;
2975 hdlr->cdataBlock = xmlSAX2CDataBlock;
2976 hdlr->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
2977 hdlr->processingInstruction = xmlSAX2ProcessingInstruction;
2978 hdlr->comment = xmlSAX2Comment;
2979 hdlr->warning = xmlParserWarning;
2980 hdlr->error = xmlParserError;
2981 hdlr->fatalError = xmlParserError;
2982
2983 hdlr->initialized = 1;
2984 }
2985
2986 /**
2987 * htmlDefaultSAXHandlerInit:
2988 *
2989 * DEPRECATED: This function will be made private. Call xmlInitParser to
2990 * initialize the library.
2991 *
2992 * Initialize the default SAX handler
2993 */
2994 void
htmlDefaultSAXHandlerInit(void)2995 htmlDefaultSAXHandlerInit(void)
2996 {
2997 xmlSAX2InitHtmlDefaultSAXHandler((xmlSAXHandlerPtr) &htmlDefaultSAXHandler);
2998 }
2999
3000 #endif /* LIBXML_HTML_ENABLED */
3001