blob: 1971aba03222ead9443e0876497fa4c069a265c0 [file] [log] [blame]
Daniel Veillard1af9a412003-08-20 22:54:39 +00001/*
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 <libxml/xmlmemory.h>
15#include <libxml/tree.h>
16#include <libxml/parser.h>
17#include <libxml/parserInternals.h>
18#include <libxml/valid.h>
19#include <libxml/entities.h>
20#include <libxml/xmlerror.h>
21#include <libxml/debugXML.h>
22#include <libxml/xmlIO.h>
23#include <libxml/SAX.h>
24#include <libxml/uri.h>
25#include <libxml/valid.h>
26#include <libxml/HTMLtree.h>
27#include <libxml/globals.h>
28
29/* #define DEBUG_SAX2 */
30/* #define DEBUG_SAX2_TREE */
31
32/**
Daniel Veillarde57ec792003-09-10 10:50:59 +000033 * TODO:
34 *
35 * macro to flag unimplemented blocks
36 * XML_CATALOG_PREFER user env to select between system/public prefered
37 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
38 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
39 *> values "system" and "public". I have made the default be "system" to
40 *> match yours.
41 */
42#define TODO \
43 xmlGenericError(xmlGenericErrorContext, \
44 "Unimplemented block at %s:%d\n", \
45 __FILE__, __LINE__);
46
47/**
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000048 * xmlValidError:
49 * @ctxt: an XML validation parser context
50 * @error: the error number
51 * @msg: the error message
52 * @str1: extra data
53 * @str2: extra data
54 *
55 * Handle a validation error
56 */
57static void
58xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error,
59 const char *msg, const char *str1, const char *str2)
60{
61 xmlStructuredErrorFunc schannel = NULL;
62
63 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
64 (ctxt->instate == XML_PARSER_EOF))
65 return;
66 ctxt->errNo = error;
67 if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
68 schannel = ctxt->sax->serror;
69 __xmlRaiseError(schannel,
70 ctxt->vctxt.error, ctxt->vctxt.userData,
71 ctxt, NULL, XML_FROM_DTD, error,
72 XML_ERR_ERROR, NULL, 0, (const char *) str1,
73 (const char *) str2, NULL, 0, 0,
74 msg, (const char *) str1, (const char *) str2);
75 ctxt->valid = 0;
76}
77
78/**
Daniel Veillard1af9a412003-08-20 22:54:39 +000079 * xmlSAX2GetPublicId:
80 * @ctx: the user data (XML parser context)
81 *
82 * Provides the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
83 *
84 * Returns a xmlChar *
85 */
86const xmlChar *
87xmlSAX2GetPublicId(void *ctx ATTRIBUTE_UNUSED)
88{
89 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
90 return(NULL);
91}
92
93/**
94 * xmlSAX2GetSystemId:
95 * @ctx: the user data (XML parser context)
96 *
97 * Provides the system ID, basically URL or filename e.g.
98 * http://www.sgmlsource.com/dtds/memo.dtd
99 *
100 * Returns a xmlChar *
101 */
102const xmlChar *
103xmlSAX2GetSystemId(void *ctx)
104{
105 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
106 return((const xmlChar *) ctxt->input->filename);
107}
108
109/**
110 * xmlSAX2GetLineNumber:
111 * @ctx: the user data (XML parser context)
112 *
113 * Provide the line number of the current parsing point.
114 *
115 * Returns an int
116 */
117int
118xmlSAX2GetLineNumber(void *ctx)
119{
120 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
121 return(ctxt->input->line);
122}
123
124/**
125 * xmlSAX2GetColumnNumber:
126 * @ctx: the user data (XML parser context)
127 *
128 * Provide the column number of the current parsing point.
129 *
130 * Returns an int
131 */
132int
133xmlSAX2GetColumnNumber(void *ctx)
134{
135 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
136 return(ctxt->input->col);
137}
138
139/**
140 * xmlSAX2IsStandalone:
141 * @ctx: the user data (XML parser context)
142 *
143 * Is this document tagged standalone ?
144 *
145 * Returns 1 if true
146 */
147int
148xmlSAX2IsStandalone(void *ctx)
149{
150 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
151 return(ctxt->myDoc->standalone == 1);
152}
153
154/**
155 * xmlSAX2HasInternalSubset:
156 * @ctx: the user data (XML parser context)
157 *
158 * Does this document has an internal subset
159 *
160 * Returns 1 if true
161 */
162int
163xmlSAX2HasInternalSubset(void *ctx)
164{
165 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
166 return(ctxt->myDoc->intSubset != NULL);
167}
168
169/**
170 * xmlSAX2HasExternalSubset:
171 * @ctx: the user data (XML parser context)
172 *
173 * Does this document has an external subset
174 *
175 * Returns 1 if true
176 */
177int
178xmlSAX2HasExternalSubset(void *ctx)
179{
180 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
181 return(ctxt->myDoc->extSubset != NULL);
182}
183
184/**
185 * xmlSAX2InternalSubset:
186 * @ctx: the user data (XML parser context)
187 * @name: the root element name
188 * @ExternalID: the external ID
189 * @SystemID: the SYSTEM ID (e.g. filename or URL)
190 *
191 * Callback on internal subset declaration.
192 */
193void
194xmlSAX2InternalSubset(void *ctx, const xmlChar *name,
195 const xmlChar *ExternalID, const xmlChar *SystemID)
196{
197 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
198 xmlDtdPtr dtd;
199#ifdef DEBUG_SAX
200 xmlGenericError(xmlGenericErrorContext,
201 "SAX.xmlSAX2InternalSubset(%s, %s, %s)\n",
202 name, ExternalID, SystemID);
203#endif
204
205 if (ctxt->myDoc == NULL)
206 return;
207 dtd = xmlGetIntSubset(ctxt->myDoc);
208 if (dtd != NULL) {
209 if (ctxt->html)
210 return;
211 xmlUnlinkNode((xmlNodePtr) dtd);
212 xmlFreeDtd(dtd);
213 ctxt->myDoc->intSubset = NULL;
214 }
215 ctxt->myDoc->intSubset =
216 xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
217}
218
219/**
220 * xmlSAX2ExternalSubset:
221 * @ctx: the user data (XML parser context)
222 * @name: the root element name
223 * @ExternalID: the external ID
224 * @SystemID: the SYSTEM ID (e.g. filename or URL)
225 *
226 * Callback on external subset declaration.
227 */
228void
229xmlSAX2ExternalSubset(void *ctx, const xmlChar *name,
230 const xmlChar *ExternalID, const xmlChar *SystemID)
231{
232 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
233#ifdef DEBUG_SAX
234 xmlGenericError(xmlGenericErrorContext,
235 "SAX.xmlSAX2ExternalSubset(%s, %s, %s)\n",
236 name, ExternalID, SystemID);
237#endif
238 if (((ExternalID != NULL) || (SystemID != NULL)) &&
239 (((ctxt->validate) || (ctxt->loadsubset != 0)) &&
240 (ctxt->wellFormed && ctxt->myDoc))) {
241 /*
242 * Try to fetch and parse the external subset.
243 */
244 xmlParserInputPtr oldinput;
245 int oldinputNr;
246 int oldinputMax;
247 xmlParserInputPtr *oldinputTab;
248 xmlParserInputPtr input = NULL;
249 xmlCharEncoding enc;
250 int oldcharset;
251
252 /*
253 * Ask the Entity resolver to load the damn thing
254 */
255 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
256 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
257 SystemID);
258 if (input == NULL) {
259 return;
260 }
261
262 xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
263
264 /*
265 * make sure we won't destroy the main document context
266 */
267 oldinput = ctxt->input;
268 oldinputNr = ctxt->inputNr;
269 oldinputMax = ctxt->inputMax;
270 oldinputTab = ctxt->inputTab;
271 oldcharset = ctxt->charset;
272
273 ctxt->inputTab = (xmlParserInputPtr *)
274 xmlMalloc(5 * sizeof(xmlParserInputPtr));
275 if (ctxt->inputTab == NULL) {
276 ctxt->errNo = XML_ERR_NO_MEMORY;
277 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
278 ctxt->sax->error(ctxt->userData,
279 "xmlSAX2ExternalSubset: out of memory\n");
280 ctxt->errNo = XML_ERR_NO_MEMORY;
281 ctxt->instate = XML_PARSER_EOF;
282 ctxt->disableSAX = 1;
283 ctxt->input = oldinput;
284 ctxt->inputNr = oldinputNr;
285 ctxt->inputMax = oldinputMax;
286 ctxt->inputTab = oldinputTab;
287 ctxt->charset = oldcharset;
288 return;
289 }
290 ctxt->inputNr = 0;
291 ctxt->inputMax = 5;
292 ctxt->input = NULL;
293 xmlPushInput(ctxt, input);
294
295 /*
296 * On the fly encoding conversion if needed
297 */
298 if (ctxt->input->length >= 4) {
299 enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
300 xmlSwitchEncoding(ctxt, enc);
301 }
302
303 if (input->filename == NULL)
304 input->filename = (char *) xmlCanonicPath(SystemID);
305 input->line = 1;
306 input->col = 1;
307 input->base = ctxt->input->cur;
308 input->cur = ctxt->input->cur;
309 input->free = NULL;
310
311 /*
312 * let's parse that entity knowing it's an external subset.
313 */
314 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
315
316 /*
317 * Free up the external entities
318 */
319
320 while (ctxt->inputNr > 1)
321 xmlPopInput(ctxt);
322 xmlFreeInputStream(ctxt->input);
323 xmlFree(ctxt->inputTab);
324
325 /*
326 * Restore the parsing context of the main entity
327 */
328 ctxt->input = oldinput;
329 ctxt->inputNr = oldinputNr;
330 ctxt->inputMax = oldinputMax;
331 ctxt->inputTab = oldinputTab;
332 ctxt->charset = oldcharset;
333 /* ctxt->wellFormed = oldwellFormed; */
334 }
335}
336
337/**
338 * xmlSAX2ResolveEntity:
339 * @ctx: the user data (XML parser context)
340 * @publicId: The public ID of the entity
341 * @systemId: The system ID of the entity
342 *
343 * The entity loader, to control the loading of external entities,
344 * the application can either:
345 * - override this xmlSAX2ResolveEntity() callback in the SAX block
346 * - or better use the xmlSetExternalEntityLoader() function to
347 * set up it's own entity resolution routine
348 *
349 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
350 */
351xmlParserInputPtr
352xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
353{
354 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
355 xmlParserInputPtr ret;
356 xmlChar *URI;
357 const char *base = NULL;
358
359 if (ctxt->input != NULL)
360 base = ctxt->input->filename;
361 if (base == NULL)
362 base = ctxt->directory;
363
364 URI = xmlBuildURI(systemId, (const xmlChar *) base);
365
366#ifdef DEBUG_SAX
367 xmlGenericError(xmlGenericErrorContext,
368 "SAX.xmlSAX2ResolveEntity(%s, %s)\n", publicId, systemId);
369#endif
370
371 ret = xmlLoadExternalEntity((const char *) URI,
372 (const char *) publicId, ctxt);
373 if (URI != NULL)
374 xmlFree(URI);
375 return(ret);
376}
377
378/**
379 * xmlSAX2GetEntity:
380 * @ctx: the user data (XML parser context)
381 * @name: The entity name
382 *
383 * Get an entity by name
384 *
385 * Returns the xmlEntityPtr if found.
386 */
387xmlEntityPtr
388xmlSAX2GetEntity(void *ctx, const xmlChar *name)
389{
390 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
391 xmlEntityPtr ret = NULL;
392
393#ifdef DEBUG_SAX
394 xmlGenericError(xmlGenericErrorContext,
395 "SAX.xmlSAX2GetEntity(%s)\n", name);
396#endif
397
398 if (ctxt->inSubset == 0) {
399 ret = xmlGetPredefinedEntity(name);
400 if (ret != NULL)
401 return(ret);
402 }
403 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->standalone == 1)) {
404 if (ctxt->inSubset == 2) {
405 ctxt->myDoc->standalone = 0;
406 ret = xmlGetDocEntity(ctxt->myDoc, name);
407 ctxt->myDoc->standalone = 1;
408 } else {
409 ret = xmlGetDocEntity(ctxt->myDoc, name);
410 if (ret == NULL) {
411 ctxt->myDoc->standalone = 0;
412 ret = xmlGetDocEntity(ctxt->myDoc, name);
413 if (ret != NULL) {
414 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000415 ctxt->sax->error(ctxt->userData,
416 "Entity(%s) document marked standalone but requires external subset\n",
Daniel Veillard1af9a412003-08-20 22:54:39 +0000417 name);
418 ctxt->valid = 0;
419 ctxt->wellFormed = 0;
420 }
421 ctxt->myDoc->standalone = 1;
422 }
423 }
424 } else {
425 ret = xmlGetDocEntity(ctxt->myDoc, name);
426 }
427 if ((ret != NULL) &&
428 ((ctxt->validate) || (ctxt->replaceEntities)) &&
429 (ret->children == NULL) &&
430 (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
431 int val;
432
433 /*
434 * for validation purposes we really need to fetch and
435 * parse the external entity
436 */
437 xmlNodePtr children;
438
439 val = xmlParseCtxtExternalEntity(ctxt, ret->URI,
440 ret->ExternalID, &children);
441 if (val == 0) {
442 xmlAddChildList((xmlNodePtr) ret, children);
443 } else {
William M. Brack4811ba32003-09-06 18:02:53 +0000444 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
445 ctxt->sax->error(ctxt->userData,
446 "Failure to process entity %s\n", name);
Daniel Veillard1af9a412003-08-20 22:54:39 +0000447 ctxt->wellFormed = 0;
448 ctxt->valid = 0;
449 ctxt->validate = 0;
450 return(NULL);
451 }
452 ret->owner = 1;
453 }
454 return(ret);
455}
456
457/**
458 * xmlSAX2GetParameterEntity:
459 * @ctx: the user data (XML parser context)
460 * @name: The entity name
461 *
462 * Get a parameter entity by name
463 *
464 * Returns the xmlEntityPtr if found.
465 */
466xmlEntityPtr
467xmlSAX2GetParameterEntity(void *ctx, const xmlChar *name)
468{
469 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
470 xmlEntityPtr ret;
471
472#ifdef DEBUG_SAX
473 xmlGenericError(xmlGenericErrorContext,
474 "SAX.xmlSAX2GetParameterEntity(%s)\n", name);
475#endif
476
477 ret = xmlGetParameterEntity(ctxt->myDoc, name);
478 return(ret);
479}
480
481
482/**
483 * xmlSAX2EntityDecl:
484 * @ctx: the user data (XML parser context)
485 * @name: the entity name
486 * @type: the entity type
487 * @publicId: The public ID of the entity
488 * @systemId: The system ID of the entity
489 * @content: the entity value (without processing).
490 *
491 * An entity definition has been parsed
492 */
493void
494xmlSAX2EntityDecl(void *ctx, const xmlChar *name, int type,
495 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
496{
497 xmlEntityPtr ent;
498 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
499
500#ifdef DEBUG_SAX
501 xmlGenericError(xmlGenericErrorContext,
502 "SAX.xmlSAX2EntityDecl(%s, %d, %s, %s, %s)\n",
503 name, type, publicId, systemId, content);
504#endif
505 if (ctxt->inSubset == 1) {
506 ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
507 systemId, content);
508 if ((ent == NULL) && (ctxt->pedantic) &&
509 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000510 ctxt->sax->warning(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000511 "Entity(%s) already defined in the internal subset\n", name);
512 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
513 xmlChar *URI;
514 const char *base = NULL;
515
516 if (ctxt->input != NULL)
517 base = ctxt->input->filename;
518 if (base == NULL)
519 base = ctxt->directory;
520
521 URI = xmlBuildURI(systemId, (const xmlChar *) base);
522 ent->URI = URI;
523 }
524 } else if (ctxt->inSubset == 2) {
525 ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
526 systemId, content);
527 if ((ent == NULL) && (ctxt->pedantic) &&
528 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000529 ctxt->sax->warning(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000530 "Entity(%s) already defined in the external subset\n", name);
531 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
532 xmlChar *URI;
533 const char *base = NULL;
534
535 if (ctxt->input != NULL)
536 base = ctxt->input->filename;
537 if (base == NULL)
538 base = ctxt->directory;
539
540 URI = xmlBuildURI(systemId, (const xmlChar *) base);
541 ent->URI = URI;
542 }
543 } else {
544 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000545 ctxt->sax->error(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000546 "SAX.xmlSAX2EntityDecl(%s) called while not in subset\n", name);
547 }
548}
549
550/**
551 * xmlSAX2AttributeDecl:
552 * @ctx: the user data (XML parser context)
553 * @elem: the name of the element
554 * @fullname: the attribute name
555 * @type: the attribute type
556 * @def: the type of default value
557 * @defaultValue: the attribute default value
558 * @tree: the tree of enumerated value set
559 *
560 * An attribute definition has been parsed
561 */
562void
563xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
564 int type, int def, const xmlChar *defaultValue,
565 xmlEnumerationPtr tree)
566{
567 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
568 xmlAttributePtr attr;
569 xmlChar *name = NULL, *prefix = NULL;
570
571#ifdef DEBUG_SAX
572 xmlGenericError(xmlGenericErrorContext,
573 "SAX.xmlSAX2AttributeDecl(%s, %s, %d, %d, %s, ...)\n",
574 elem, fullname, type, def, defaultValue);
575#endif
Daniel Veillarde57ec792003-09-10 10:50:59 +0000576 /* TODO: optimize name/prefix allocation */
Daniel Veillard1af9a412003-08-20 22:54:39 +0000577 name = xmlSplitQName(ctxt, fullname, &prefix);
578 ctxt->vctxt.valid = 1;
579 if (ctxt->inSubset == 1)
580 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
581 name, prefix, (xmlAttributeType) type,
582 (xmlAttributeDefault) def, defaultValue, tree);
583 else if (ctxt->inSubset == 2)
584 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
585 name, prefix, (xmlAttributeType) type,
586 (xmlAttributeDefault) def, defaultValue, tree);
587 else {
588 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000589 ctxt->sax->error(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000590 "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n", name);
Daniel Veillarde57ec792003-09-10 10:50:59 +0000591 xmlFreeEnumeration(tree);
Daniel Veillard1af9a412003-08-20 22:54:39 +0000592 return;
593 }
Daniel Veillard4432df22003-09-28 18:58:27 +0000594#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +0000595 if (ctxt->vctxt.valid == 0)
596 ctxt->valid = 0;
597 if ((attr != NULL) && (ctxt->validate) && (ctxt->wellFormed) &&
598 (ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset != NULL))
599 ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
600 attr);
Daniel Veillard4432df22003-09-28 18:58:27 +0000601#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +0000602 if (prefix != NULL)
603 xmlFree(prefix);
604 if (name != NULL)
605 xmlFree(name);
606}
607
608/**
609 * xmlSAX2ElementDecl:
610 * @ctx: the user data (XML parser context)
611 * @name: the element name
612 * @type: the element type
613 * @content: the element value tree
614 *
615 * An element definition has been parsed
616 */
617void
618xmlSAX2ElementDecl(void *ctx, const xmlChar * name, int type,
619 xmlElementContentPtr content)
620{
621 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
622 xmlElementPtr elem = NULL;
623
624#ifdef DEBUG_SAX
625 xmlGenericError(xmlGenericErrorContext,
626 "SAX.xmlSAX2ElementDecl(%s, %d, ...)\n", name, type);
627#endif
628
629 if (ctxt->inSubset == 1)
630 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
631 name, (xmlElementTypeVal) type, content);
632 else if (ctxt->inSubset == 2)
633 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
634 name, (xmlElementTypeVal) type, content);
635 else {
636 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000637 ctxt->sax->error(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000638 "SAX.xmlSAX2ElementDecl(%s) called while not in subset\n",
639 name);
640 return;
641 }
Daniel Veillard4432df22003-09-28 18:58:27 +0000642#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +0000643 if (elem == NULL)
644 ctxt->valid = 0;
645 if (ctxt->validate && ctxt->wellFormed &&
646 ctxt->myDoc && ctxt->myDoc->intSubset)
647 ctxt->valid &=
648 xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
Daniel Veillard4432df22003-09-28 18:58:27 +0000649#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +0000650}
651
652/**
653 * xmlSAX2NotationDecl:
654 * @ctx: the user data (XML parser context)
655 * @name: The name of the notation
656 * @publicId: The public ID of the entity
657 * @systemId: The system ID of the entity
658 *
659 * What to do when a notation declaration has been parsed.
660 */
661void
662xmlSAX2NotationDecl(void *ctx, const xmlChar *name,
663 const xmlChar *publicId, const xmlChar *systemId)
664{
665 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
666 xmlNotationPtr nota = NULL;
667
668#ifdef DEBUG_SAX
669 xmlGenericError(xmlGenericErrorContext,
670 "SAX.xmlSAX2NotationDecl(%s, %s, %s)\n", name, publicId, systemId);
671#endif
672
673 if ((publicId == NULL) && (systemId == NULL)) {
674 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000675 ctxt->sax->error(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000676 "SAX.xmlSAX2NotationDecl(%s) externalID or PublicID missing\n", name);
677 ctxt->valid = 0;
678 ctxt->wellFormed = 0;
679 return;
680 } else if (ctxt->inSubset == 1)
681 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
682 publicId, systemId);
683 else if (ctxt->inSubset == 2)
684 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, name,
685 publicId, systemId);
686 else {
687 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000688 ctxt->sax->error(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000689 "SAX.xmlSAX2NotationDecl(%s) called while not in subset\n", name);
690 return;
691 }
Daniel Veillard4432df22003-09-28 18:58:27 +0000692#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +0000693 if (nota == NULL) ctxt->valid = 0;
694 if (ctxt->validate && ctxt->wellFormed &&
695 ctxt->myDoc && ctxt->myDoc->intSubset)
696 ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
697 nota);
Daniel Veillard4432df22003-09-28 18:58:27 +0000698#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +0000699}
700
701/**
702 * xmlSAX2UnparsedEntityDecl:
703 * @ctx: the user data (XML parser context)
704 * @name: The name of the entity
705 * @publicId: The public ID of the entity
706 * @systemId: The system ID of the entity
707 * @notationName: the name of the notation
708 *
709 * What to do when an unparsed entity declaration is parsed
710 */
711void
712xmlSAX2UnparsedEntityDecl(void *ctx, const xmlChar *name,
713 const xmlChar *publicId, const xmlChar *systemId,
714 const xmlChar *notationName)
715{
716 xmlEntityPtr ent;
717 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
718#ifdef DEBUG_SAX
719 xmlGenericError(xmlGenericErrorContext,
720 "SAX.xmlSAX2UnparsedEntityDecl(%s, %s, %s, %s)\n",
721 name, publicId, systemId, notationName);
722#endif
723 if (ctxt->inSubset == 1) {
724 ent = xmlAddDocEntity(ctxt->myDoc, name,
725 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
726 publicId, systemId, notationName);
727 if ((ent == NULL) && (ctxt->pedantic) &&
728 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000729 ctxt->sax->warning(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000730 "Entity(%s) already defined in the internal subset\n", name);
731 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
732 xmlChar *URI;
733 const char *base = NULL;
734
735 if (ctxt->input != NULL)
736 base = ctxt->input->filename;
737 if (base == NULL)
738 base = ctxt->directory;
739
740 URI = xmlBuildURI(systemId, (const xmlChar *) base);
741 ent->URI = URI;
742 }
743 } else if (ctxt->inSubset == 2) {
744 ent = xmlAddDtdEntity(ctxt->myDoc, name,
745 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
746 publicId, systemId, notationName);
747 if ((ent == NULL) && (ctxt->pedantic) &&
748 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000749 ctxt->sax->warning(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000750 "Entity(%s) already defined in the external subset\n", name);
751 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
752 xmlChar *URI;
753 const char *base = NULL;
754
755 if (ctxt->input != NULL)
756 base = ctxt->input->filename;
757 if (base == NULL)
758 base = ctxt->directory;
759
760 URI = xmlBuildURI(systemId, (const xmlChar *) base);
761 ent->URI = URI;
762 }
763 } else {
764 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +0000765 ctxt->sax->error(ctxt->userData,
Daniel Veillard1af9a412003-08-20 22:54:39 +0000766 "SAX.xmlSAX2UnparsedEntityDecl(%s) called while not in subset\n", name);
767 }
768}
769
770/**
771 * xmlSAX2SetDocumentLocator:
772 * @ctx: the user data (XML parser context)
773 * @loc: A SAX Locator
774 *
775 * Receive the document locator at startup, actually xmlDefaultSAXLocator
776 * Everything is available on the context, so this is useless in our case.
777 */
778void
779xmlSAX2SetDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
780{
781 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
782#ifdef DEBUG_SAX
783 xmlGenericError(xmlGenericErrorContext,
784 "SAX.xmlSAX2SetDocumentLocator()\n");
785#endif
786}
787
788/**
789 * xmlSAX2StartDocument:
790 * @ctx: the user data (XML parser context)
791 *
792 * called when the document start being processed.
793 */
794void
795xmlSAX2StartDocument(void *ctx)
796{
797 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
798 xmlDocPtr doc;
799
800#ifdef DEBUG_SAX
801 xmlGenericError(xmlGenericErrorContext,
802 "SAX.xmlSAX2StartDocument()\n");
803#endif
804 if (ctxt->html) {
805#ifdef LIBXML_HTML_ENABLED
806 if (ctxt->myDoc == NULL)
807 ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
808 if (ctxt->myDoc == NULL) {
809 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
810 ctxt->sax->error(ctxt->userData,
811 "SAX.xmlSAX2StartDocument(): out of memory\n");
812 ctxt->errNo = XML_ERR_NO_MEMORY;
813 ctxt->instate = XML_PARSER_EOF;
814 ctxt->disableSAX = 1;
815 return;
816 }
817#else
818 xmlGenericError(xmlGenericErrorContext,
819 "libxml2 built without HTML support\n");
820 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
821 ctxt->instate = XML_PARSER_EOF;
822 ctxt->disableSAX = 1;
823 return;
824#endif
825 } else {
826 doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
827 if (doc != NULL) {
828 if (ctxt->encoding != NULL)
829 doc->encoding = xmlStrdup(ctxt->encoding);
830 else
831 doc->encoding = NULL;
832 doc->standalone = ctxt->standalone;
833 } else {
834 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
835 ctxt->sax->error(ctxt->userData,
836 "SAX.xmlSAX2StartDocument(): out of memory\n");
837 ctxt->errNo = XML_ERR_NO_MEMORY;
838 ctxt->instate = XML_PARSER_EOF;
839 ctxt->disableSAX = 1;
840 return;
841 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000842 if ((ctxt->dictNames) && (doc != NULL))
843 doc->dict = ctxt->dict;
Daniel Veillard1af9a412003-08-20 22:54:39 +0000844 }
845 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
846 (ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
847 ctxt->myDoc->URL = xmlCanonicPath((const xmlChar *) ctxt->input->filename);
848 if (ctxt->myDoc->URL == NULL)
849 ctxt->myDoc->URL = xmlStrdup((const xmlChar *) ctxt->input->filename);
850 }
851}
852
853/**
854 * xmlSAX2EndDocument:
855 * @ctx: the user data (XML parser context)
856 *
857 * called when the document end has been detected.
858 */
859void
860xmlSAX2EndDocument(void *ctx)
861{
862 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
863#ifdef DEBUG_SAX
864 xmlGenericError(xmlGenericErrorContext,
865 "SAX.xmlSAX2EndDocument()\n");
866#endif
Daniel Veillard4432df22003-09-28 18:58:27 +0000867#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +0000868 if (ctxt->validate && ctxt->wellFormed &&
869 ctxt->myDoc && ctxt->myDoc->intSubset)
870 ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc);
Daniel Veillard4432df22003-09-28 18:58:27 +0000871#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +0000872
873 /*
874 * Grab the encoding if it was added on-the-fly
875 */
876 if ((ctxt->encoding != NULL) && (ctxt->myDoc != NULL) &&
877 (ctxt->myDoc->encoding == NULL)) {
878 ctxt->myDoc->encoding = ctxt->encoding;
879 ctxt->encoding = NULL;
880 }
881 if ((ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
882 (ctxt->myDoc->encoding == NULL)) {
883 ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
884 }
885 if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) &&
886 (ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) {
887 ctxt->myDoc->charset = ctxt->charset;
888 }
889}
890
Daniel Veillard81273902003-09-30 00:43:48 +0000891#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED)
Daniel Veillard1af9a412003-08-20 22:54:39 +0000892/**
893 * xmlSAX2AttributeInternal:
894 * @ctx: the user data (XML parser context)
895 * @fullname: The attribute name, including namespace prefix
896 * @value: The attribute value
897 * @prefix: the prefix on the element node
898 *
899 * Handle an attribute that has been read by the parser.
900 * The default handling is to convert the attribute into an
901 * DOM subtree and past it in a new xmlAttr element added to
902 * the element.
903 */
904static void
905xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000906 const xmlChar *value, const xmlChar *prefix ATTRIBUTE_UNUSED)
Daniel Veillard1af9a412003-08-20 22:54:39 +0000907{
908 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
909 xmlAttrPtr ret;
910 xmlChar *name;
911 xmlChar *ns;
912 xmlChar *nval;
913 xmlNsPtr namespace;
914
915 /*
916 * Split the full name into a namespace prefix and the tag name
917 */
918 name = xmlSplitQName(ctxt, fullname, &ns);
919 if ((name != NULL) && (name[0] == 0)) {
920 if (xmlStrEqual(ns, BAD_CAST "xmlns")) {
921 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
922 ctxt->sax->error(ctxt->userData,
923 "invalid namespace declaration '%s'\n", fullname);
924 } else {
925 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
926 ctxt->sax->warning(ctxt->userData,
927 "Avoid attribute ending with ':' like '%s'\n", fullname);
928 }
929 if (ns != NULL)
930 xmlFree(ns);
931 ns = NULL;
932 xmlFree(name);
933 name = xmlStrdup(fullname);
934 }
935 if (name == NULL) {
936 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
937 ctxt->sax->error(ctxt->userData,
938 "SAX.xmlSAX2StartElement(): out of memory\n");
939 ctxt->errNo = XML_ERR_NO_MEMORY;
940 ctxt->instate = XML_PARSER_EOF;
941 ctxt->disableSAX = 1;
942 if (ns != NULL)
943 xmlFree(ns);
944 return;
945 }
946
Daniel Veillard4432df22003-09-28 18:58:27 +0000947#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +0000948 /*
949 * Do the last stage of the attribute normalization
950 * Needed for HTML too:
951 * http://www.w3.org/TR/html4/types.html#h-6.2
952 */
953 ctxt->vctxt.valid = 1;
954 nval = xmlValidCtxtNormalizeAttributeValue(&ctxt->vctxt,
955 ctxt->myDoc, ctxt->node,
956 fullname, value);
957 if (ctxt->vctxt.valid != 1) {
958 ctxt->valid = 0;
959 }
960 if (nval != NULL)
961 value = nval;
Daniel Veillard4432df22003-09-28 18:58:27 +0000962#else
963 nval = NULL;
964#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +0000965
966 /*
967 * Check whether it's a namespace definition
968 */
969 if ((!ctxt->html) && (ns == NULL) &&
970 (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
971 (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
972 xmlNsPtr nsret;
973 xmlChar *val;
974
975 if (!ctxt->replaceEntities) {
976 ctxt->depth++;
977 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
978 0,0,0);
979 ctxt->depth--;
980 } else {
981 val = (xmlChar *) value;
982 }
983
984 if (val[0] != 0) {
985 xmlURIPtr uri;
986
987 uri = xmlParseURI((const char *)val);
988 if (uri == NULL) {
989 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
990 ctxt->sax->warning(ctxt->userData,
William M. Brack4811ba32003-09-06 18:02:53 +0000991 "xmlns: %s not a valid URI\n", val);
Daniel Veillard1af9a412003-08-20 22:54:39 +0000992 } else {
993 if (uri->scheme == NULL) {
994 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
995 ctxt->sax->warning(ctxt->userData,
996 "xmlns: URI %s is not absolute\n", val);
997 }
998 xmlFreeURI(uri);
999 }
1000 }
1001
1002 /* a default namespace definition */
1003 nsret = xmlNewNs(ctxt->node, val, NULL);
1004
Daniel Veillard4432df22003-09-28 18:58:27 +00001005#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +00001006 /*
1007 * Validate also for namespace decls, they are attributes from
1008 * an XML-1.0 perspective
1009 */
1010 if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
1011 ctxt->myDoc && ctxt->myDoc->intSubset)
1012 ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
1013 ctxt->node, prefix, nsret, val);
Daniel Veillard4432df22003-09-28 18:58:27 +00001014#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +00001015 if (name != NULL)
1016 xmlFree(name);
1017 if (nval != NULL)
1018 xmlFree(nval);
1019 if (val != value)
1020 xmlFree(val);
1021 return;
1022 }
1023 if ((!ctxt->html) &&
1024 (ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
1025 (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
1026 xmlNsPtr nsret;
1027 xmlChar *val;
1028
1029 if (!ctxt->replaceEntities) {
1030 ctxt->depth++;
1031 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
1032 0,0,0);
1033 ctxt->depth--;
1034 if (val == NULL) {
1035 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1036 ctxt->sax->error(ctxt->userData,
1037 "SAX.xmlSAX2StartElement(): out of memory\n");
1038 ctxt->errNo = XML_ERR_NO_MEMORY;
1039 ctxt->instate = XML_PARSER_EOF;
1040 ctxt->disableSAX = 1;
1041 xmlFree(ns);
1042 if (name != NULL)
1043 xmlFree(name);
1044 return;
1045 }
1046 } else {
1047 val = (xmlChar *) value;
1048 }
1049
1050 if (val[0] == 0) {
1051 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1052 ctxt->sax->error(ctxt->userData,
1053 "Empty namespace name for prefix %s\n", name);
1054 }
1055 if ((ctxt->pedantic != 0) && (val[0] != 0)) {
1056 xmlURIPtr uri;
1057
1058 uri = xmlParseURI((const char *)val);
1059 if (uri == NULL) {
1060 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1061 ctxt->sax->warning(ctxt->userData,
1062 "xmlns:%s: %s not a valid URI\n", name, value);
1063 } else {
1064 if (uri->scheme == NULL) {
1065 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1066 ctxt->sax->warning(ctxt->userData,
1067 "xmlns:%s: URI %s is not absolute\n", name, value);
1068 }
1069 xmlFreeURI(uri);
1070 }
1071 }
1072
1073 /* a standard namespace definition */
1074 nsret = xmlNewNs(ctxt->node, val, name);
1075 xmlFree(ns);
Daniel Veillard4432df22003-09-28 18:58:27 +00001076#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +00001077 /*
1078 * Validate also for namespace decls, they are attributes from
1079 * an XML-1.0 perspective
1080 */
1081 if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
1082 ctxt->myDoc && ctxt->myDoc->intSubset)
1083 ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
1084 ctxt->node, prefix, nsret, value);
Daniel Veillard4432df22003-09-28 18:58:27 +00001085#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +00001086 if (name != NULL)
1087 xmlFree(name);
1088 if (nval != NULL)
1089 xmlFree(nval);
1090 if (val != value)
1091 xmlFree(val);
1092 return;
1093 }
1094
1095 if (ns != NULL) {
1096 xmlAttrPtr prop;
1097 namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
Daniel Veillard67906942003-08-28 21:13:25 +00001098 if (namespace == NULL) {
William M. Brack4811ba32003-09-06 18:02:53 +00001099 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1100 ctxt->sax->error(ctxt->userData,
1101 "Namespace prefix %s of attribute %s is not defined\n",
Daniel Veillard67906942003-08-28 21:13:25 +00001102 ns, name);
1103 }
Daniel Veillard1af9a412003-08-20 22:54:39 +00001104
1105 prop = ctxt->node->properties;
1106 while (prop != NULL) {
1107 if (prop->ns != NULL) {
1108 if ((xmlStrEqual(name, prop->name)) &&
1109 ((namespace == prop->ns) ||
1110 (xmlStrEqual(namespace->href, prop->ns->href)))) {
1111 ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED;
1112 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1113 ctxt->sax->error(ctxt->userData,
1114 "Attribute %s in %s redefined\n",
1115 name, namespace->href);
1116 ctxt->wellFormed = 0;
1117 if (ctxt->recovery == 0) ctxt->disableSAX = 1;
1118 goto error;
1119 }
1120 }
1121 prop = prop->next;
1122 }
1123 } else {
1124 namespace = NULL;
1125 }
1126
1127 /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */
1128 ret = xmlNewNsPropEatName(ctxt->node, namespace, name, NULL);
1129
1130 if (ret != NULL) {
1131 if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
1132 xmlNodePtr tmp;
1133
1134 ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
1135 tmp = ret->children;
1136 while (tmp != NULL) {
1137 tmp->parent = (xmlNodePtr) ret;
1138 if (tmp->next == NULL)
1139 ret->last = tmp;
1140 tmp = tmp->next;
1141 }
1142 } else if (value != NULL) {
1143 ret->children = xmlNewDocText(ctxt->myDoc, value);
1144 ret->last = ret->children;
1145 if (ret->children != NULL)
1146 ret->children->parent = (xmlNodePtr) ret;
1147 }
1148 }
1149
Daniel Veillard4432df22003-09-28 18:58:27 +00001150#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +00001151 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
1152 ctxt->myDoc && ctxt->myDoc->intSubset) {
1153
1154 /*
1155 * If we don't substitute entities, the validation should be
1156 * done on a value with replaced entities anyway.
1157 */
1158 if (!ctxt->replaceEntities) {
1159 xmlChar *val;
1160
1161 ctxt->depth++;
1162 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
1163 0,0,0);
1164 ctxt->depth--;
1165
1166 if (val == NULL)
1167 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1168 ctxt->myDoc, ctxt->node, ret, value);
1169 else {
1170 xmlChar *nvalnorm;
1171
1172 /*
1173 * Do the last stage of the attribute normalization
1174 * It need to be done twice ... it's an extra burden related
1175 * to the ability to keep xmlSAX2References in attributes
1176 */
1177 nvalnorm = xmlValidNormalizeAttributeValue(ctxt->myDoc,
1178 ctxt->node, fullname, val);
1179 if (nvalnorm != NULL) {
1180 xmlFree(val);
1181 val = nvalnorm;
1182 }
1183
1184 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1185 ctxt->myDoc, ctxt->node, ret, val);
1186 xmlFree(val);
1187 }
1188 } else {
1189 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
1190 ctxt->node, ret, value);
1191 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001192 } else
1193#endif /* LIBXML_VALID_ENABLED */
1194 if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) &&
Daniel Veillard1af9a412003-08-20 22:54:39 +00001195 (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
1196 ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0)))) {
1197 /*
1198 * when validating, the ID registration is done at the attribute
1199 * validation level. Otherwise we have to do specific handling here.
1200 */
1201 if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
1202 xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
1203 else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
1204 xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
1205 }
1206
1207error:
1208 if (nval != NULL)
1209 xmlFree(nval);
1210 if (ns != NULL)
1211 xmlFree(ns);
1212}
1213
Daniel Veillard1af9a412003-08-20 22:54:39 +00001214/*
1215 * xmlCheckDefaultedAttributes:
1216 *
1217 * Check defaulted attributes from the DTD
1218 */
1219static void
1220xmlCheckDefaultedAttributes(xmlParserCtxtPtr ctxt, const xmlChar *name,
1221 const xmlChar *prefix, const xmlChar **atts) {
1222 xmlElementPtr elemDecl;
1223 const xmlChar *att;
1224 int internal = 1;
1225 int i;
1226
1227 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->intSubset, name, prefix);
1228 if (elemDecl == NULL) {
1229 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset, name, prefix);
1230 internal = 0;
1231 }
1232
1233process_external_subset:
1234
1235 if (elemDecl != NULL) {
1236 xmlAttributePtr attr = elemDecl->attributes;
1237 /*
1238 * Check against defaulted attributes from the external subset
1239 * if the document is stamped as standalone
1240 */
1241 if ((ctxt->myDoc->standalone == 1) &&
1242 (ctxt->myDoc->extSubset != NULL) &&
1243 (ctxt->validate)) {
1244 while (attr != NULL) {
1245 if ((attr->defaultValue != NULL) &&
1246 (xmlGetDtdQAttrDesc(ctxt->myDoc->extSubset,
1247 attr->elem, attr->name,
1248 attr->prefix) == attr) &&
1249 (xmlGetDtdQAttrDesc(ctxt->myDoc->intSubset,
1250 attr->elem, attr->name,
1251 attr->prefix) == NULL)) {
1252 xmlChar *fulln;
1253
1254 if (attr->prefix != NULL) {
1255 fulln = xmlStrdup(attr->prefix);
1256 fulln = xmlStrcat(fulln, BAD_CAST ":");
1257 fulln = xmlStrcat(fulln, attr->name);
1258 } else {
1259 fulln = xmlStrdup(attr->name);
1260 }
1261
1262 /*
1263 * Check that the attribute is not declared in the
1264 * serialization
1265 */
1266 att = NULL;
1267 if (atts != NULL) {
1268 i = 0;
1269 att = atts[i];
1270 while (att != NULL) {
1271 if (xmlStrEqual(att, fulln))
1272 break;
1273 i += 2;
1274 att = atts[i];
1275 }
1276 }
1277 if (att == NULL) {
Daniel Veillardf88d8cf2003-12-08 10:25:02 +00001278 xmlErrValid(ctxt, XML_DTD_STANDALONE_DEFAULTED,
Daniel Veillard1af9a412003-08-20 22:54:39 +00001279 "standalone: attribute %s on %s defaulted from external subset\n",
Daniel Veillardf88d8cf2003-12-08 10:25:02 +00001280 fulln, attr->elem);
Daniel Veillard1af9a412003-08-20 22:54:39 +00001281 }
1282 }
1283 attr = attr->nexth;
1284 }
1285 }
1286
1287 /*
1288 * Actually insert defaulted values when needed
1289 */
1290 attr = elemDecl->attributes;
1291 while (attr != NULL) {
1292 /*
1293 * Make sure that attributes redefinition occuring in the
1294 * internal subset are not overriden by definitions in the
1295 * external subset.
1296 */
1297 if (attr->defaultValue != NULL) {
1298 /*
1299 * the element should be instantiated in the tree if:
1300 * - this is a namespace prefix
1301 * - the user required for completion in the tree
1302 * like XSLT
1303 * - there isn't already an attribute definition
1304 * in the internal subset overriding it.
1305 */
1306 if (((attr->prefix != NULL) &&
1307 (xmlStrEqual(attr->prefix, BAD_CAST "xmlns"))) ||
1308 ((attr->prefix == NULL) &&
1309 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) ||
1310 (ctxt->loadsubset & XML_COMPLETE_ATTRS)) {
1311 xmlAttributePtr tst;
1312
1313 tst = xmlGetDtdQAttrDesc(ctxt->myDoc->intSubset,
1314 attr->elem, attr->name,
1315 attr->prefix);
1316 if ((tst == attr) || (tst == NULL)) {
1317 xmlChar fn[50];
1318 xmlChar *fulln;
1319
1320 fulln = xmlBuildQName(attr->name, attr->prefix, fn, 50);
1321 if (fulln == NULL) {
1322 if ((ctxt->sax != NULL) &&
1323 (ctxt->sax->error != NULL))
1324 ctxt->sax->error(ctxt->userData,
1325 "SAX.xmlSAX2StartElement(): out of memory\n");
1326 ctxt->errNo = XML_ERR_NO_MEMORY;
1327 ctxt->instate = XML_PARSER_EOF;
1328 ctxt->disableSAX = 1;
1329 return;
1330 }
1331
1332 /*
1333 * Check that the attribute is not declared in the
1334 * serialization
1335 */
1336 att = NULL;
1337 if (atts != NULL) {
1338 i = 0;
1339 att = atts[i];
1340 while (att != NULL) {
1341 if (xmlStrEqual(att, fulln))
1342 break;
1343 i += 2;
1344 att = atts[i];
1345 }
1346 }
1347 if (att == NULL) {
1348 xmlSAX2AttributeInternal(ctxt, fulln,
1349 attr->defaultValue, prefix);
1350 }
1351 if ((fulln != fn) && (fulln != attr->name))
1352 xmlFree(fulln);
1353 }
1354 }
1355 }
1356 attr = attr->nexth;
1357 }
1358 if (internal == 1) {
1359 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset,
1360 name, prefix);
1361 internal = 0;
1362 goto process_external_subset;
1363 }
1364 }
1365}
1366
1367/**
1368 * xmlSAX2StartElement:
1369 * @ctx: the user data (XML parser context)
1370 * @fullname: The element name, including namespace prefix
1371 * @atts: An array of name/value attributes pairs, NULL terminated
1372 *
1373 * called when an opening tag has been processed.
1374 */
1375void
1376xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
1377{
1378 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1379 xmlNodePtr ret;
1380 xmlNodePtr parent = ctxt->node;
1381 xmlNsPtr ns;
1382 xmlChar *name;
1383 xmlChar *prefix;
1384 const xmlChar *att;
1385 const xmlChar *value;
1386 int i;
1387
1388#ifdef DEBUG_SAX
1389 xmlGenericError(xmlGenericErrorContext,
1390 "SAX.xmlSAX2StartElement(%s)\n", fullname);
1391#endif
1392
1393 /*
1394 * First check on validity:
1395 */
1396 if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
1397 ((ctxt->myDoc->intSubset == NULL) ||
1398 ((ctxt->myDoc->intSubset->notations == NULL) &&
1399 (ctxt->myDoc->intSubset->elements == NULL) &&
1400 (ctxt->myDoc->intSubset->attributes == NULL) &&
1401 (ctxt->myDoc->intSubset->entities == NULL)))) {
Daniel Veillardf88d8cf2003-12-08 10:25:02 +00001402 xmlErrValid(ctxt, XML_ERR_NO_DTD,
1403 "Validation failed: no DTD found !", NULL, NULL);
Daniel Veillard1af9a412003-08-20 22:54:39 +00001404 ctxt->validate = 0;
Daniel Veillard1af9a412003-08-20 22:54:39 +00001405 }
1406
1407
1408 /*
1409 * Split the full name into a namespace prefix and the tag name
1410 */
1411 name = xmlSplitQName(ctxt, fullname, &prefix);
1412
1413
1414 /*
1415 * Note : the namespace resolution is deferred until the end of the
1416 * attributes parsing, since local namespace can be defined as
1417 * an attribute at this level.
1418 */
1419 ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL);
1420 if (ret == NULL) {
1421 if (prefix != NULL)
1422 xmlFree(prefix);
1423 ctxt->errNo = XML_ERR_NO_MEMORY;
1424 ctxt->instate = XML_PARSER_EOF;
1425 ctxt->disableSAX = 1;
1426 return;
1427 }
1428 if (ctxt->myDoc->children == NULL) {
1429#ifdef DEBUG_SAX_TREE
1430 xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
1431#endif
1432 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1433 } else if (parent == NULL) {
1434 parent = ctxt->myDoc->children;
1435 }
1436 ctxt->nodemem = -1;
1437 if (ctxt->linenumbers) {
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00001438 if (ctxt->input != NULL) {
1439 if (ctxt->input->line < 65535)
1440 ret->line = (short) ctxt->input->line;
1441 else
1442 ret->line = 65535;
1443 }
Daniel Veillard1af9a412003-08-20 22:54:39 +00001444 }
1445
1446 /*
1447 * We are parsing a new node.
1448 */
1449#ifdef DEBUG_SAX_TREE
1450 xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name);
1451#endif
1452 nodePush(ctxt, ret);
1453
1454 /*
1455 * Link the child element
1456 */
1457 if (parent != NULL) {
1458 if (parent->type == XML_ELEMENT_NODE) {
1459#ifdef DEBUG_SAX_TREE
1460 xmlGenericError(xmlGenericErrorContext,
1461 "adding child %s to %s\n", name, parent->name);
1462#endif
1463 xmlAddChild(parent, ret);
1464 } else {
1465#ifdef DEBUG_SAX_TREE
1466 xmlGenericError(xmlGenericErrorContext,
1467 "adding sibling %s to ", name);
1468 xmlDebugDumpOneNode(stderr, parent, 0);
1469#endif
1470 xmlAddSibling(parent, ret);
1471 }
1472 }
1473
1474 /*
1475 * Insert all the defaulted attributes from the DTD especially namespaces
1476 */
1477 if ((!ctxt->html) &&
1478 ((ctxt->myDoc->intSubset != NULL) ||
1479 (ctxt->myDoc->extSubset != NULL))) {
1480 xmlCheckDefaultedAttributes(ctxt, name, prefix, atts);
1481 }
1482
1483 /*
1484 * process all the attributes whose name start with "xmlns"
1485 */
1486 if (atts != NULL) {
1487 i = 0;
1488 att = atts[i++];
1489 value = atts[i++];
1490 if (!ctxt->html) {
1491 while ((att != NULL) && (value != NULL)) {
1492 if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l') &&
1493 (att[3] == 'n') && (att[4] == 's'))
1494 xmlSAX2AttributeInternal(ctxt, att, value, prefix);
1495
1496 att = atts[i++];
1497 value = atts[i++];
1498 }
1499 }
1500 }
1501
1502 /*
1503 * Search the namespace, note that since the attributes have been
1504 * processed, the local namespaces are available.
1505 */
1506 ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
1507 if ((ns == NULL) && (parent != NULL))
1508 ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
1509 if ((prefix != NULL) && (ns == NULL)) {
1510 ns = xmlNewNs(ret, NULL, prefix);
1511 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1512 ctxt->sax->warning(ctxt->userData,
1513 "Namespace prefix %s is not defined\n", prefix);
1514 }
1515
1516 /*
1517 * set the namespace node, making sure that if the default namspace
1518 * is unbound on a parent we simply kee it NULL
1519 */
1520 if ((ns != NULL) && (ns->href != NULL) &&
1521 ((ns->href[0] != 0) || (ns->prefix != NULL)))
1522 xmlSetNs(ret, ns);
1523
1524 /*
1525 * process all the other attributes
1526 */
1527 if (atts != NULL) {
1528 i = 0;
1529 att = atts[i++];
1530 value = atts[i++];
1531 if (ctxt->html) {
1532 while (att != NULL) {
1533 xmlSAX2AttributeInternal(ctxt, att, value, NULL);
1534 att = atts[i++];
1535 value = atts[i++];
1536 }
1537 } else {
1538 while ((att != NULL) && (value != NULL)) {
1539 if ((att[0] != 'x') || (att[1] != 'm') || (att[2] != 'l') ||
1540 (att[3] != 'n') || (att[4] != 's'))
1541 xmlSAX2AttributeInternal(ctxt, att, value, NULL);
1542
1543 /*
1544 * Next ones
1545 */
1546 att = atts[i++];
1547 value = atts[i++];
1548 }
1549 }
1550 }
1551
Daniel Veillard4432df22003-09-28 18:58:27 +00001552#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +00001553 /*
1554 * If it's the Document root, finish the DTD validation and
1555 * check the document root element for validity
1556 */
1557 if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) {
1558 int chk;
1559
1560 chk = xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
1561 if (chk <= 0)
1562 ctxt->valid = 0;
1563 if (chk < 0)
1564 ctxt->wellFormed = 0;
1565 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
1566 ctxt->vctxt.finishDtd = 1;
1567 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001568#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +00001569
1570 if (prefix != NULL)
1571 xmlFree(prefix);
1572
1573}
1574
1575/**
1576 * xmlSAX2EndElement:
1577 * @ctx: the user data (XML parser context)
1578 * @name: The element name
1579 *
1580 * called when the end of an element has been detected.
1581 */
1582void
1583xmlSAX2EndElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED)
1584{
1585 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1586 xmlParserNodeInfo node_info;
1587 xmlNodePtr cur = ctxt->node;
1588
1589#ifdef DEBUG_SAX
1590 if (name == NULL)
1591 xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2EndElement(NULL)\n");
1592 else
1593 xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2EndElement(%s)\n", name);
1594#endif
1595
1596 /* Capture end position and add node */
1597 if (cur != NULL && ctxt->record_info) {
1598 node_info.end_pos = ctxt->input->cur - ctxt->input->base;
1599 node_info.end_line = ctxt->input->line;
1600 node_info.node = cur;
1601 xmlParserAddNodeInfo(ctxt, &node_info);
1602 }
1603 ctxt->nodemem = -1;
1604
Daniel Veillard4432df22003-09-28 18:58:27 +00001605#ifdef LIBXML_VALID_ENABLED
Daniel Veillard1af9a412003-08-20 22:54:39 +00001606 if (ctxt->validate && ctxt->wellFormed &&
1607 ctxt->myDoc && ctxt->myDoc->intSubset)
1608 ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc,
1609 cur);
Daniel Veillard4432df22003-09-28 18:58:27 +00001610#endif /* LIBXML_VALID_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +00001611
1612
1613 /*
1614 * end of parsing of this node.
1615 */
1616#ifdef DEBUG_SAX_TREE
1617 xmlGenericError(xmlGenericErrorContext, "popping(%s)\n", cur->name);
1618#endif
1619 nodePop(ctxt);
1620}
Daniel Veillard81273902003-09-30 00:43:48 +00001621#endif /* LIBXML_SAX1_ENABLED || LIBXML_HTML_ENABLE */
Daniel Veillard1af9a412003-08-20 22:54:39 +00001622
Daniel Veillarde57ec792003-09-10 10:50:59 +00001623/*
Daniel Veillard19895052003-09-17 13:59:32 +00001624 * xmlSAX2TextNode:
1625 * @ctxt: the parser context
1626 * @str: the input string
1627 * @len: the string length
1628 *
1629 * Remove the entities from an attribute value
1630 *
1631 * Returns the newly allocated string or NULL if not needed or error
1632 */
1633static xmlNodePtr
1634xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
1635 xmlNodePtr ret;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001636 const xmlChar *intern = NULL;
Daniel Veillard19895052003-09-17 13:59:32 +00001637
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001638 /*
1639 * Allocate
1640 */
Daniel Veillard19895052003-09-17 13:59:32 +00001641 if (ctxt->freeElems != NULL) {
1642 ret = ctxt->freeElems;
1643 ctxt->freeElems = ret->next;
1644 ctxt->freeElemsNr--;
Daniel Veillard19895052003-09-17 13:59:32 +00001645 } else {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001646 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard19895052003-09-17 13:59:32 +00001647 }
1648 if (ret == NULL) {
1649 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1650 ctxt->sax->error(ctxt->userData,
1651 "SAX.xmlSAX2Characters(): out of memory\n");
1652 ctxt->errNo = XML_ERR_NO_MEMORY;
1653 ctxt->instate = XML_PARSER_EOF;
1654 ctxt->disableSAX = 1;
1655 return(NULL);
1656 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001657 /*
1658 * intern the formatting blanks found between tags, or the
1659 * very short strings
1660 */
1661 if (ctxt->dictNames) {
1662 xmlChar cur = str[len];
1663
Daniel Veillarddca8cc72003-09-26 13:53:14 +00001664 if ((len <= 3) && ((cur == '"') || (cur == '\'') ||
1665 ((cur == '<') && (str[len + 1] != '!')))) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001666 intern = xmlDictLookup(ctxt->dict, str, len);
William M. Brack76e95df2003-10-18 16:20:14 +00001667 } else if (IS_BLANK_CH(*str) && (len < 60) && (cur == '<') &&
Daniel Veillarddca8cc72003-09-26 13:53:14 +00001668 (str[len + 1] != '!')) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001669 int i;
1670
1671 for (i = 1;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00001672 if (!IS_BLANK_CH(*str)) goto skip;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001673 }
1674 intern = xmlDictLookup(ctxt->dict, str, len);
1675 }
1676 }
1677skip:
1678 memset(ret, 0, sizeof(xmlNode));
1679 ret->type = XML_TEXT_NODE;
1680
1681 ret->name = xmlStringText;
1682 if (intern == NULL)
1683 ret->content = xmlStrndup(str, len);
1684 else
1685 ret->content = (xmlChar *) intern;
1686
1687 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1688 xmlRegisterNodeDefaultValue(ret);
Daniel Veillard19895052003-09-17 13:59:32 +00001689 return(ret);
1690}
1691
Daniel Veillard4432df22003-09-28 18:58:27 +00001692#ifdef LIBXML_VALID_ENABLED
Daniel Veillard19895052003-09-17 13:59:32 +00001693/*
Daniel Veillarde57ec792003-09-10 10:50:59 +00001694 * xmlSAX2DecodeAttrEntities:
1695 * @ctxt: the parser context
1696 * @str: the input string
1697 * @len: the string length
1698 *
1699 * Remove the entities from an attribute value
1700 *
1701 * Returns the newly allocated string or NULL if not needed or error
1702 */
1703static xmlChar *
1704xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str,
1705 const xmlChar *end) {
1706 const xmlChar *in;
1707 xmlChar *ret;
1708
1709 in = str;
1710 while (in < end)
1711 if (*in++ == '&')
1712 goto decode;
1713 return(NULL);
1714decode:
1715 ctxt->depth++;
1716 ret = xmlStringLenDecodeEntities(ctxt, str, end - str,
1717 XML_SUBSTITUTE_REF, 0,0,0);
1718 ctxt->depth--;
1719 return(ret);
1720}
Daniel Veillard4432df22003-09-28 18:58:27 +00001721#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarde57ec792003-09-10 10:50:59 +00001722
1723/**
1724 * xmlSAX2AttributeNs:
1725 * @ctx: the user data (XML parser context)
Daniel Veillard62998c02003-09-15 12:56:36 +00001726 * @localname: the local name of the attribute
1727 * @prefix: the attribute namespace prefix if available
1728 * @URI: the attribute namespace name if available
Daniel Veillarde57ec792003-09-10 10:50:59 +00001729 * @value: Start of the attribute value
1730 * @valueend: end of the attribute value
1731 *
1732 * Handle an attribute that has been read by the parser.
1733 * The default handling is to convert the attribute into an
1734 * DOM subtree and past it in a new xmlAttr element added to
1735 * the element.
1736 */
1737static void
1738xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt,
1739 const xmlChar * localname,
1740 const xmlChar * prefix,
1741 const xmlChar * value,
1742 const xmlChar * valueend)
1743{
1744 xmlAttrPtr ret;
1745 xmlNsPtr namespace = NULL;
1746 xmlChar *dup = NULL;
1747
Daniel Veillarde57ec792003-09-10 10:50:59 +00001748 /*
1749 * Note: if prefix == NULL, the attribute is not in the default namespace
1750 */
1751 if (prefix != NULL)
1752 namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix);
1753
Daniel Veillard8a44e592003-09-15 14:50:06 +00001754 /*
1755 * allocate the node
1756 */
1757 if (ctxt->freeAttrs != NULL) {
1758 ret = ctxt->freeAttrs;
1759 ctxt->freeAttrs = ret->next;
Daniel Veillard19895052003-09-17 13:59:32 +00001760 ctxt->freeAttrsNr--;
Daniel Veillard8a44e592003-09-15 14:50:06 +00001761 memset(ret, 0, sizeof(xmlAttr));
1762 ret->type = XML_ATTRIBUTE_NODE;
Daniel Veillarde57ec792003-09-10 10:50:59 +00001763
Daniel Veillard8a44e592003-09-15 14:50:06 +00001764 ret->parent = ctxt->node;
1765 ret->doc = ctxt->myDoc;
1766 ret->ns = namespace;
Daniel Veillarde57ec792003-09-10 10:50:59 +00001767
Daniel Veillard8a44e592003-09-15 14:50:06 +00001768 if (ctxt->dictNames)
1769 ret->name = localname;
1770 else
1771 ret->name = xmlStrdup(localname);
1772
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001773 /* link at the end to preserv order, TODO speed up with a last */
1774 if (ctxt->node->properties == NULL) {
1775 ctxt->node->properties = ret;
1776 } else {
1777 xmlAttrPtr prev = ctxt->node->properties;
1778
1779 while (prev->next != NULL) prev = prev->next;
1780 prev->next = ret;
1781 ret->prev = prev;
1782 }
1783
Daniel Veillard8a44e592003-09-15 14:50:06 +00001784 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1785 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
1786 } else {
1787 if (ctxt->dictNames)
1788 ret = xmlNewNsPropEatName(ctxt->node, namespace,
1789 (xmlChar *) localname, NULL);
1790 else
1791 ret = xmlNewNsProp(ctxt->node, namespace, localname, NULL);
1792 if (ret == NULL) {
1793 ctxt->errNo = XML_ERR_NO_MEMORY;
1794 ctxt->instate = XML_PARSER_EOF;
1795 ctxt->disableSAX = 1;
1796 return;
Daniel Veillarde57ec792003-09-10 10:50:59 +00001797 }
1798 }
1799
Daniel Veillard8a44e592003-09-15 14:50:06 +00001800 if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
1801 xmlNodePtr tmp;
1802
Daniel Veillard19895052003-09-17 13:59:32 +00001803 /*
1804 * We know that if there is an entity reference, then
1805 * the string has been dup'ed and terminates with 0
1806 * otherwise with ' or "
1807 */
1808 if (*valueend != 0) {
1809 tmp = xmlSAX2TextNode(ctxt, value, valueend - value);
1810 ret->children = tmp;
1811 ret->last = tmp;
1812 if (tmp != NULL) {
1813 tmp->doc = ret->doc;
1814 tmp->parent = (xmlNodePtr) ret;
1815 }
1816 } else {
1817 ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value,
1818 valueend - value);
1819 tmp = ret->children;
1820 while (tmp != NULL) {
1821 tmp->parent = (xmlNodePtr) ret;
1822 if (tmp->next == NULL)
1823 ret->last = tmp;
1824 tmp = tmp->next;
1825 }
Daniel Veillard8a44e592003-09-15 14:50:06 +00001826 }
1827 } else if (value != NULL) {
Daniel Veillard19895052003-09-17 13:59:32 +00001828 xmlNodePtr tmp;
1829
1830 tmp = xmlSAX2TextNode(ctxt, value, valueend - value);
1831 ret->children = tmp;
1832 ret->last = tmp;
1833 if (tmp != NULL) {
1834 tmp->doc = ret->doc;
1835 tmp->parent = (xmlNodePtr) ret;
1836 }
Daniel Veillard8a44e592003-09-15 14:50:06 +00001837 }
1838
Daniel Veillard4432df22003-09-28 18:58:27 +00001839#ifdef LIBXML_VALID_ENABLED
Daniel Veillarde57ec792003-09-10 10:50:59 +00001840 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
1841 ctxt->myDoc && ctxt->myDoc->intSubset) {
1842 /*
1843 * If we don't substitute entities, the validation should be
1844 * done on a value with replaced entities anyway.
1845 */
1846 if (!ctxt->replaceEntities) {
1847 dup = xmlSAX2DecodeAttrEntities(ctxt, value, valueend);
1848 if (dup == NULL) {
Daniel Veillard62998c02003-09-15 12:56:36 +00001849 if (*valueend == 0) {
1850 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1851 ctxt->myDoc, ctxt->node, ret, value);
1852 } else {
1853 /*
1854 * That should already be normalized.
1855 * cheaper to finally allocate here than duplicate
1856 * entry points in the full validation code
1857 */
1858 dup = xmlStrndup(value, valueend - value);
Daniel Veillarde57ec792003-09-10 10:50:59 +00001859
Daniel Veillard62998c02003-09-15 12:56:36 +00001860 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1861 ctxt->myDoc, ctxt->node, ret, dup);
1862 }
Daniel Veillarde57ec792003-09-10 10:50:59 +00001863 } else {
Daniel Veillard62998c02003-09-15 12:56:36 +00001864 /*
1865 * dup now contains a string of the flattened attribute
1866 * content with entities substitued. Check if we need to
1867 * apply an extra layer of normalization.
Daniel Veillarde57ec792003-09-10 10:50:59 +00001868 * It need to be done twice ... it's an extra burden related
1869 * to the ability to keep references in attributes
1870 */
Daniel Veillard62998c02003-09-15 12:56:36 +00001871 if (ctxt->attsSpecial != NULL) {
1872 xmlChar *nvalnorm;
1873 xmlChar fn[50];
1874 xmlChar *fullname;
1875
1876 fullname = xmlBuildQName(localname, prefix, fn, 50);
1877 if (fullname != NULL) {
1878 ctxt->vctxt.valid = 1;
1879 nvalnorm = xmlValidCtxtNormalizeAttributeValue(
1880 &ctxt->vctxt, ctxt->myDoc,
1881 ctxt->node, fullname, dup);
1882 if (ctxt->vctxt.valid != 1)
1883 ctxt->valid = 0;
1884
1885 if ((fullname != fn) && (fullname != localname))
1886 xmlFree(fullname);
1887 if (nvalnorm != NULL) {
1888 xmlFree(dup);
1889 dup = nvalnorm;
1890 }
1891 }
Daniel Veillarde57ec792003-09-10 10:50:59 +00001892 }
Daniel Veillarde57ec792003-09-10 10:50:59 +00001893
1894 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1895 ctxt->myDoc, ctxt->node, ret, dup);
1896 }
1897 } else {
Daniel Veillard8e36e6a2003-09-10 10:50:59 +00001898 /*
1899 * if entities already have been substitued, then
1900 * the attribute as passed is already normalized
1901 */
Daniel Veillarde57ec792003-09-10 10:50:59 +00001902 dup = xmlStrndup(value, valueend - value);
1903
1904 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
1905 ctxt->myDoc, ctxt->node, ret, dup);
1906 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001907 } else
1908#endif /* LIBXML_VALID_ENABLED */
1909 if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) &&
Daniel Veillarde57ec792003-09-10 10:50:59 +00001910 (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
1911 ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0)))) {
1912 /*
1913 * when validating, the ID registration is done at the attribute
1914 * validation level. Otherwise we have to do specific handling here.
1915 */
1916 if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) {
1917 /* might be worth duplicate entry points and not copy */
1918 if (dup == NULL)
1919 dup = xmlStrndup(value, valueend - value);
1920 xmlAddID(&ctxt->vctxt, ctxt->myDoc, dup, ret);
1921 } else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) {
1922 if (dup == NULL)
1923 dup = xmlStrndup(value, valueend - value);
1924 xmlAddRef(&ctxt->vctxt, ctxt->myDoc, dup, ret);
1925 }
1926 }
1927 if (dup != NULL)
1928 xmlFree(dup);
1929}
1930
1931/**
1932 * xmlSAX2StartElementNs:
1933 * @ctx: the user data (XML parser context)
1934 * @localname: the local name of the element
1935 * @prefix: the element namespace prefix if available
1936 * @URI: the element namespace name if available
1937 * @nb_namespaces: number of namespace definitions on that node
1938 * @namespaces: pointer to the array of prefix/URI pairs namespace definitions
1939 * @nb_attributes: the number of attributes on that node
Daniel Veillard7a02cfe2003-09-25 12:18:34 +00001940 * @nb_defaulted: the number of defaulted attributes.
Daniel Veillarde57ec792003-09-10 10:50:59 +00001941 * @attributes: pointer to the array of (localname/prefix/URI/value/end)
1942 * attribute values.
1943 *
1944 * SAX2 callback when an element start has been detected by the parser.
1945 * It provides the namespace informations for the element, as well as
1946 * the new namespace declarations on the element.
1947 */
1948void
1949xmlSAX2StartElementNs(void *ctx,
1950 const xmlChar *localname,
1951 const xmlChar *prefix,
1952 const xmlChar *URI,
1953 int nb_namespaces,
1954 const xmlChar **namespaces,
1955 int nb_attributes,
1956 int nb_defaulted,
1957 const xmlChar **attributes)
1958{
1959 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1960 xmlNodePtr ret;
1961 xmlNodePtr parent = ctxt->node;
1962 xmlNsPtr last = NULL, ns;
1963 const xmlChar *uri, *pref;
1964 int i, j;
1965
1966 /*
1967 * First check on validity:
1968 */
1969 if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
1970 ((ctxt->myDoc->intSubset == NULL) ||
1971 ((ctxt->myDoc->intSubset->notations == NULL) &&
1972 (ctxt->myDoc->intSubset->elements == NULL) &&
1973 (ctxt->myDoc->intSubset->attributes == NULL) &&
1974 (ctxt->myDoc->intSubset->entities == NULL)))) {
Daniel Veillardf88d8cf2003-12-08 10:25:02 +00001975 xmlErrValid(ctxt, XML_ERR_NO_DTD,
1976 "Validation failed: no DTD found !", NULL, NULL);
Daniel Veillarde57ec792003-09-10 10:50:59 +00001977 ctxt->validate = 0;
Daniel Veillarde57ec792003-09-10 10:50:59 +00001978 }
1979
Daniel Veillard8a44e592003-09-15 14:50:06 +00001980 /*
1981 * allocate the node
1982 */
1983 if (ctxt->freeElems != NULL) {
1984 ret = ctxt->freeElems;
1985 ctxt->freeElems = ret->next;
Daniel Veillard19895052003-09-17 13:59:32 +00001986 ctxt->freeElemsNr--;
Daniel Veillard8a44e592003-09-15 14:50:06 +00001987 memset(ret, 0, sizeof(xmlNode));
1988 ret->type = XML_ELEMENT_NODE;
1989
1990 if (ctxt->dictNames)
1991 ret->name = localname;
1992 else
1993 ret->name = xmlStrdup(localname);
1994
1995 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1996 xmlRegisterNodeDefaultValue(ret);
1997 } else {
1998 if (ctxt->dictNames)
1999 ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL,
2000 (xmlChar *) localname, NULL);
2001 else
2002 ret = xmlNewDocNode(ctxt->myDoc, NULL, localname, NULL);
2003 if (ret == NULL) {
2004 ctxt->errNo = XML_ERR_NO_MEMORY;
2005 ctxt->instate = XML_PARSER_EOF;
2006 ctxt->disableSAX = 1;
2007 return;
2008 }
Daniel Veillarde57ec792003-09-10 10:50:59 +00002009 }
Daniel Veillardd9e9c9d2003-09-18 22:03:46 +00002010 if (ctxt->linenumbers) {
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00002011 if (ctxt->input != NULL) {
2012 if (ctxt->input->line < 65535)
2013 ret->line = (short) ctxt->input->line;
2014 else
2015 ret->line = 65535;
2016 }
Daniel Veillardd9e9c9d2003-09-18 22:03:46 +00002017 }
Daniel Veillard8a44e592003-09-15 14:50:06 +00002018
Daniel Veillarde57ec792003-09-10 10:50:59 +00002019 if (ctxt->myDoc->children == NULL) {
2020 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
2021 } else if (parent == NULL) {
2022 parent = ctxt->myDoc->children;
2023 }
2024 /*
2025 * Build the namespace list
2026 */
2027 for (i = 0,j = 0;j < nb_namespaces;j++) {
2028 pref = namespaces[i++];
2029 uri = namespaces[i++];
2030 ns = xmlNewNs(NULL, uri, pref);
2031 if (ns != NULL) {
2032 if (last == NULL) {
2033 ret->nsDef = last = ns;
2034 } else {
2035 last->next = ns;
2036 last = ns;
2037 }
2038 if ((URI != NULL) && (prefix == pref))
2039 ret->ns = ns;
2040 } else {
2041 ctxt->errNo = XML_ERR_NO_MEMORY;
2042 ctxt->instate = XML_PARSER_EOF;
2043 ctxt->disableSAX = 1;
2044 return;
2045 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002046#ifdef LIBXML_VALID_ENABLED
Daniel Veillardd9e9c9d2003-09-18 22:03:46 +00002047 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
2048 ctxt->myDoc && ctxt->myDoc->intSubset) {
2049 ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
2050 ret, prefix, ns, uri);
2051 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002052#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarde57ec792003-09-10 10:50:59 +00002053 }
2054 ctxt->nodemem = -1;
Daniel Veillarde57ec792003-09-10 10:50:59 +00002055
2056 /*
2057 * We are parsing a new node.
2058 */
2059 nodePush(ctxt, ret);
2060
2061 /*
2062 * Link the child element
2063 */
2064 if (parent != NULL) {
2065 if (parent->type == XML_ELEMENT_NODE) {
2066 xmlAddChild(parent, ret);
2067 } else {
2068 xmlAddSibling(parent, ret);
2069 }
2070 }
2071
2072 /*
2073 * Insert the defaulted attributes from the DTD only if requested:
2074 */
2075 if ((nb_defaulted != 0) &&
2076 ((ctxt->loadsubset & XML_COMPLETE_ATTRS) == 0))
2077 nb_attributes -= nb_defaulted;
2078
2079 /*
2080 * Search the namespace if it wasn't already found
2081 */
2082 if ((URI != NULL) && (ret->ns == NULL)) {
2083 ret->ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
2084 if (ret->ns == NULL) {
2085 ns = xmlNewNs(ret, NULL, prefix);
2086 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
2087 ctxt->sax->warning(ctxt->userData,
2088 "Namespace prefix %s was not found\n", prefix);
2089 }
2090 }
2091
2092 /*
2093 * process all the other attributes
2094 */
2095 if (nb_attributes > 0) {
2096 for (j = 0,i = 0;i < nb_attributes;i++,j+=5) {
2097 xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1],
2098 attributes[j+3], attributes[j+4]);
2099 }
2100 }
2101
Daniel Veillard4432df22003-09-28 18:58:27 +00002102#ifdef LIBXML_VALID_ENABLED
Daniel Veillarde57ec792003-09-10 10:50:59 +00002103 /*
2104 * If it's the Document root, finish the DTD validation and
2105 * check the document root element for validity
2106 */
2107 if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) {
2108 int chk;
2109
2110 chk = xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
2111 if (chk <= 0)
2112 ctxt->valid = 0;
2113 if (chk < 0)
2114 ctxt->wellFormed = 0;
2115 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
2116 ctxt->vctxt.finishDtd = 1;
2117 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002118#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarde57ec792003-09-10 10:50:59 +00002119}
2120
2121/**
2122 * xmlSAX2EndElementNs:
2123 * @ctx: the user data (XML parser context)
2124 * @localname: the local name of the element
2125 * @prefix: the element namespace prefix if available
2126 * @URI: the element namespace name if available
2127 *
2128 * SAX2 callback when an element end has been detected by the parser.
2129 * It provides the namespace informations for the element.
2130 */
2131void
2132xmlSAX2EndElementNs(void *ctx,
2133 const xmlChar * localname ATTRIBUTE_UNUSED,
2134 const xmlChar * prefix ATTRIBUTE_UNUSED,
2135 const xmlChar * URI ATTRIBUTE_UNUSED)
2136{
2137 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2138 xmlParserNodeInfo node_info;
2139 xmlNodePtr cur = ctxt->node;
2140
2141 /* Capture end position and add node */
2142 if ((ctxt->record_info) && (cur != NULL)) {
2143 node_info.end_pos = ctxt->input->cur - ctxt->input->base;
2144 node_info.end_line = ctxt->input->line;
2145 node_info.node = cur;
2146 xmlParserAddNodeInfo(ctxt, &node_info);
2147 }
2148 ctxt->nodemem = -1;
2149
Daniel Veillard4432df22003-09-28 18:58:27 +00002150#ifdef LIBXML_VALID_ENABLED
Daniel Veillarde57ec792003-09-10 10:50:59 +00002151 if (ctxt->validate && ctxt->wellFormed &&
2152 ctxt->myDoc && ctxt->myDoc->intSubset)
2153 ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc, cur);
Daniel Veillard4432df22003-09-28 18:58:27 +00002154#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarde57ec792003-09-10 10:50:59 +00002155
2156 /*
2157 * end of parsing of this node.
2158 */
2159 nodePop(ctxt);
2160}
2161
Daniel Veillard1af9a412003-08-20 22:54:39 +00002162/**
2163 * xmlSAX2Reference:
2164 * @ctx: the user data (XML parser context)
2165 * @name: The entity name
2166 *
2167 * called when an entity xmlSAX2Reference is detected.
2168 */
2169void
2170xmlSAX2Reference(void *ctx, const xmlChar *name)
2171{
2172 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2173 xmlNodePtr ret;
2174
2175#ifdef DEBUG_SAX
2176 xmlGenericError(xmlGenericErrorContext,
2177 "SAX.xmlSAX2Reference(%s)\n", name);
2178#endif
2179 if (name[0] == '#')
2180 ret = xmlNewCharRef(ctxt->myDoc, name);
2181 else
2182 ret = xmlNewReference(ctxt->myDoc, name);
2183#ifdef DEBUG_SAX_TREE
2184 xmlGenericError(xmlGenericErrorContext,
2185 "add xmlSAX2Reference %s to %s \n", name, ctxt->node->name);
2186#endif
2187 xmlAddChild(ctxt->node, ret);
2188}
2189
2190/**
2191 * xmlSAX2Characters:
2192 * @ctx: the user data (XML parser context)
2193 * @ch: a xmlChar string
2194 * @len: the number of xmlChar
2195 *
2196 * receiving some chars from the parser.
2197 */
2198void
2199xmlSAX2Characters(void *ctx, const xmlChar *ch, int len)
2200{
2201 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2202 xmlNodePtr lastChild;
2203
2204#ifdef DEBUG_SAX
2205 xmlGenericError(xmlGenericErrorContext,
2206 "SAX.xmlSAX2Characters(%.30s, %d)\n", ch, len);
2207#endif
2208 /*
2209 * Handle the data if any. If there is no child
2210 * add it as content, otherwise if the last child is text,
2211 * concatenate it, else create a new node of type text.
2212 */
2213
2214 if (ctxt->node == NULL) {
2215#ifdef DEBUG_SAX_TREE
2216 xmlGenericError(xmlGenericErrorContext,
2217 "add chars: ctxt->node == NULL !\n");
2218#endif
2219 return;
2220 }
Daniel Veillard19895052003-09-17 13:59:32 +00002221 lastChild = ctxt->node->last;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002222#ifdef DEBUG_SAX_TREE
2223 xmlGenericError(xmlGenericErrorContext,
2224 "add chars to %s \n", ctxt->node->name);
2225#endif
2226
2227 /*
2228 * Here we needed an accelerator mechanism in case of very large
2229 * elements. Use an attribute in the structure !!!
2230 */
2231 if (lastChild == NULL) {
Daniel Veillard19895052003-09-17 13:59:32 +00002232 lastChild = xmlSAX2TextNode(ctxt, ch, len);
2233 if (lastChild != NULL) {
2234 ctxt->node->children = lastChild;
2235 ctxt->node->last = lastChild;
2236 lastChild->parent = ctxt->node;
2237 lastChild->doc = ctxt->node->doc;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002238 ctxt->nodelen = len;
2239 ctxt->nodemem = len + 1;
2240 }
2241 } else {
2242 int coalesceText = (lastChild != NULL) &&
2243 (lastChild->type == XML_TEXT_NODE) &&
2244 (lastChild->name == xmlStringText);
2245 if ((coalesceText) && (ctxt->nodemem != 0)) {
2246 /*
2247 * The whole point of maintaining nodelen and nodemem,
2248 * xmlTextConcat is too costly, i.e. compute length,
2249 * reallocate a new buffer, move data, append ch. Here
2250 * We try to minimaze realloc() uses and avoid copying
2251 * and recomputing length over and over.
2252 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +00002253 if ((ctxt->nodemem == ctxt->nodelen + 1) &&
2254 (xmlDictOwns(ctxt->dict, lastChild->content))) {
2255 lastChild->content = xmlStrdup(lastChild->content);
2256 }
Daniel Veillard1af9a412003-08-20 22:54:39 +00002257 if (ctxt->nodelen + len >= ctxt->nodemem) {
2258 xmlChar *newbuf;
2259 int size;
2260
2261 size = ctxt->nodemem + len;
2262 size *= 2;
2263 newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
2264 if (newbuf == NULL) {
2265 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2266 ctxt->sax->error(ctxt->userData,
2267 "SAX.xmlSAX2Characters(): out of memory\n");
2268 ctxt->errNo = XML_ERR_NO_MEMORY;
2269 ctxt->instate = XML_PARSER_EOF;
2270 ctxt->disableSAX = 1;
2271 return;
2272 }
2273 ctxt->nodemem = size;
2274 lastChild->content = newbuf;
2275 }
2276 memcpy(&lastChild->content[ctxt->nodelen], ch, len);
2277 ctxt->nodelen += len;
2278 lastChild->content[ctxt->nodelen] = 0;
2279 } else if (coalesceText) {
2280 if (xmlTextConcat(lastChild, ch, len)) {
2281 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2282 ctxt->sax->error(ctxt->userData,
2283 "SAX.xmlSAX2Characters(): out of memory\n");
2284 ctxt->errNo = XML_ERR_NO_MEMORY;
2285 ctxt->instate = XML_PARSER_EOF;
2286 ctxt->disableSAX = 1;
2287 }
2288 if (ctxt->node->children != NULL) {
2289 ctxt->nodelen = xmlStrlen(lastChild->content);
2290 ctxt->nodemem = ctxt->nodelen + 1;
2291 }
2292 } else {
2293 /* Mixed content, first time */
Daniel Veillard19895052003-09-17 13:59:32 +00002294 lastChild = xmlSAX2TextNode(ctxt, ch, len);
2295 if (lastChild != NULL) {
Daniel Veillard1af9a412003-08-20 22:54:39 +00002296 xmlAddChild(ctxt->node, lastChild);
2297 if (ctxt->node->children != NULL) {
2298 ctxt->nodelen = len;
2299 ctxt->nodemem = len + 1;
2300 }
2301 }
2302 }
2303 }
2304}
2305
2306/**
2307 * xmlSAX2IgnorableWhitespace:
2308 * @ctx: the user data (XML parser context)
2309 * @ch: a xmlChar string
2310 * @len: the number of xmlChar
2311 *
2312 * receiving some ignorable whitespaces from the parser.
2313 * UNUSED: by default the DOM building will use xmlSAX2Characters
2314 */
2315void
2316xmlSAX2IgnorableWhitespace(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch ATTRIBUTE_UNUSED, int len ATTRIBUTE_UNUSED)
2317{
2318 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
2319#ifdef DEBUG_SAX
2320 xmlGenericError(xmlGenericErrorContext,
2321 "SAX.xmlSAX2IgnorableWhitespace(%.30s, %d)\n", ch, len);
2322#endif
2323}
2324
2325/**
2326 * xmlSAX2ProcessingInstruction:
2327 * @ctx: the user data (XML parser context)
2328 * @target: the target name
2329 * @data: the PI data's
2330 *
2331 * A processing instruction has been parsed.
2332 */
2333void
2334xmlSAX2ProcessingInstruction(void *ctx, const xmlChar *target,
2335 const xmlChar *data)
2336{
2337 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2338 xmlNodePtr ret;
2339 xmlNodePtr parent = ctxt->node;
2340
2341#ifdef DEBUG_SAX
2342 xmlGenericError(xmlGenericErrorContext,
2343 "SAX.xmlSAX2ProcessingInstruction(%s, %s)\n", target, data);
2344#endif
2345
2346 ret = xmlNewPI(target, data);
2347 if (ret == NULL) return;
2348 parent = ctxt->node;
2349
2350 if (ctxt->inSubset == 1) {
2351 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
2352 return;
2353 } else if (ctxt->inSubset == 2) {
2354 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
2355 return;
2356 }
2357 if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
2358#ifdef DEBUG_SAX_TREE
2359 xmlGenericError(xmlGenericErrorContext,
2360 "Setting PI %s as root\n", target);
2361#endif
2362 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
2363 return;
2364 }
2365 if (parent->type == XML_ELEMENT_NODE) {
2366#ifdef DEBUG_SAX_TREE
2367 xmlGenericError(xmlGenericErrorContext,
2368 "adding PI %s child to %s\n", target, parent->name);
2369#endif
2370 xmlAddChild(parent, ret);
2371 } else {
2372#ifdef DEBUG_SAX_TREE
2373 xmlGenericError(xmlGenericErrorContext,
2374 "adding PI %s sibling to ", target);
2375 xmlDebugDumpOneNode(stderr, parent, 0);
2376#endif
2377 xmlAddSibling(parent, ret);
2378 }
2379}
2380
2381/**
2382 * xmlSAX2Comment:
2383 * @ctx: the user data (XML parser context)
2384 * @value: the xmlSAX2Comment content
2385 *
2386 * A xmlSAX2Comment has been parsed.
2387 */
2388void
2389xmlSAX2Comment(void *ctx, const xmlChar *value)
2390{
2391 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2392 xmlNodePtr ret;
2393 xmlNodePtr parent = ctxt->node;
2394
2395#ifdef DEBUG_SAX
2396 xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2Comment(%s)\n", value);
2397#endif
2398 ret = xmlNewDocComment(ctxt->myDoc, value);
2399 if (ret == NULL) return;
2400
2401 if (ctxt->inSubset == 1) {
2402 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
2403 return;
2404 } else if (ctxt->inSubset == 2) {
2405 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
2406 return;
2407 }
2408 if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
2409#ifdef DEBUG_SAX_TREE
2410 xmlGenericError(xmlGenericErrorContext,
2411 "Setting xmlSAX2Comment as root\n");
2412#endif
2413 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
2414 return;
2415 }
2416 if (parent->type == XML_ELEMENT_NODE) {
2417#ifdef DEBUG_SAX_TREE
2418 xmlGenericError(xmlGenericErrorContext,
2419 "adding xmlSAX2Comment child to %s\n", parent->name);
2420#endif
2421 xmlAddChild(parent, ret);
2422 } else {
2423#ifdef DEBUG_SAX_TREE
2424 xmlGenericError(xmlGenericErrorContext,
2425 "adding xmlSAX2Comment sibling to ");
2426 xmlDebugDumpOneNode(stderr, parent, 0);
2427#endif
2428 xmlAddSibling(parent, ret);
2429 }
2430}
2431
2432/**
2433 * xmlSAX2CDataBlock:
2434 * @ctx: the user data (XML parser context)
2435 * @value: The pcdata content
2436 * @len: the block length
2437 *
2438 * called when a pcdata block has been parsed
2439 */
2440void
2441xmlSAX2CDataBlock(void *ctx, const xmlChar *value, int len)
2442{
2443 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
2444 xmlNodePtr ret, lastChild;
2445
2446#ifdef DEBUG_SAX
2447 xmlGenericError(xmlGenericErrorContext,
2448 "SAX.pcdata(%.10s, %d)\n", value, len);
2449#endif
2450 lastChild = xmlGetLastChild(ctxt->node);
2451#ifdef DEBUG_SAX_TREE
2452 xmlGenericError(xmlGenericErrorContext,
2453 "add chars to %s \n", ctxt->node->name);
2454#endif
2455 if ((lastChild != NULL) &&
2456 (lastChild->type == XML_CDATA_SECTION_NODE)) {
2457 xmlTextConcat(lastChild, value, len);
2458 } else {
2459 ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
2460 xmlAddChild(ctxt->node, ret);
2461 }
2462}
2463
Daniel Veillard62998c02003-09-15 12:56:36 +00002464static int xmlSAX2DefaultVersionValue = 2;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002465
Daniel Veillard81273902003-09-30 00:43:48 +00002466#ifdef LIBXML_SAX1_ENABLED
Daniel Veillarde57ec792003-09-10 10:50:59 +00002467/**
2468 * xmlSAXDefaultVersion:
2469 * @version: the version, 1 or 2
2470 *
2471 * Set the default version of SAX used globally by the library.
2472 * Note that this may not be a good thing to do from a library
2473 * it is better to use xmlSAXVersion() to set up specifically the
2474 * version for a given parsing context.
2475 *
2476 * Returns the previous value in case of success and -1 in case of error.
2477 */
2478int
2479xmlSAXDefaultVersion(int version)
2480{
2481 int ret = xmlSAX2DefaultVersionValue;
2482
2483 if ((version != 1) && (version != 2))
2484 return(-1);
2485 xmlSAX2DefaultVersionValue = version;
Daniel Veillarde57ec792003-09-10 10:50:59 +00002486 return(ret);
2487}
Daniel Veillard81273902003-09-30 00:43:48 +00002488#endif /* LIBXML_SAX1_ENABLED */
Daniel Veillarde57ec792003-09-10 10:50:59 +00002489
2490/**
2491 * xmlSAXVersion:
2492 * @hdlr: the SAX handler
2493 * @version: the version, 1 or 2
2494 *
2495 * Initialize the default XML SAX handler according to the version
2496 *
2497 * Returns 0 in case of success and -1 in case of error.
2498 */
2499int
2500xmlSAXVersion(xmlSAXHandler *hdlr, int version)
2501{
2502 if (hdlr == NULL) return(-1);
Daniel Veillard81273902003-09-30 00:43:48 +00002503 if (version == 2) {
Daniel Veillarde57ec792003-09-10 10:50:59 +00002504 hdlr->startElement = NULL;
2505 hdlr->endElement = NULL;
2506 hdlr->startElementNs = xmlSAX2StartElementNs;
2507 hdlr->endElementNs = xmlSAX2EndElementNs;
Daniel Veillardffbbed42003-10-10 14:46:54 +00002508 hdlr->serror = NULL;
Daniel Veillard092643b2003-09-25 14:29:29 +00002509 hdlr->initialized = XML_SAX2_MAGIC;
Daniel Veillard81273902003-09-30 00:43:48 +00002510#ifdef LIBXML_SAX1_ENABLED
2511 } else if (version == 1) {
2512 hdlr->startElement = xmlSAX2StartElement;
2513 hdlr->endElement = xmlSAX2EndElement;
2514 hdlr->initialized = 1;
2515#endif /* LIBXML_SAX1_ENABLED */
Daniel Veillarde57ec792003-09-10 10:50:59 +00002516 } else
2517 return(-1);
Daniel Veillard1af9a412003-08-20 22:54:39 +00002518 hdlr->internalSubset = xmlSAX2InternalSubset;
2519 hdlr->externalSubset = xmlSAX2ExternalSubset;
2520 hdlr->isStandalone = xmlSAX2IsStandalone;
2521 hdlr->hasInternalSubset = xmlSAX2HasInternalSubset;
2522 hdlr->hasExternalSubset = xmlSAX2HasExternalSubset;
2523 hdlr->resolveEntity = xmlSAX2ResolveEntity;
2524 hdlr->getEntity = xmlSAX2GetEntity;
2525 hdlr->getParameterEntity = xmlSAX2GetParameterEntity;
2526 hdlr->entityDecl = xmlSAX2EntityDecl;
2527 hdlr->attributeDecl = xmlSAX2AttributeDecl;
2528 hdlr->elementDecl = xmlSAX2ElementDecl;
2529 hdlr->notationDecl = xmlSAX2NotationDecl;
2530 hdlr->unparsedEntityDecl = xmlSAX2UnparsedEntityDecl;
2531 hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator;
2532 hdlr->startDocument = xmlSAX2StartDocument;
2533 hdlr->endDocument = xmlSAX2EndDocument;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002534 hdlr->reference = xmlSAX2Reference;
2535 hdlr->characters = xmlSAX2Characters;
2536 hdlr->cdataBlock = xmlSAX2CDataBlock;
2537 hdlr->ignorableWhitespace = xmlSAX2Characters;
2538 hdlr->processingInstruction = xmlSAX2ProcessingInstruction;
2539 hdlr->comment = xmlSAX2Comment;
Daniel Veillarde57ec792003-09-10 10:50:59 +00002540 hdlr->warning = xmlParserWarning;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002541 hdlr->error = xmlParserError;
2542 hdlr->fatalError = xmlParserError;
2543
Daniel Veillarde57ec792003-09-10 10:50:59 +00002544 return(0);
2545}
2546
2547/**
2548 * xmlSAX2InitDefaultSAXHandler:
2549 * @hdlr: the SAX handler
2550 * @warning: flag if non-zero sets the handler warning procedure
2551 *
2552 * Initialize the default XML SAX2 handler
2553 */
2554void
2555xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning)
2556{
2557 if ((hdlr == NULL) || (hdlr->initialized != 0))
2558 return;
2559
2560 xmlSAXVersion(hdlr, xmlSAX2DefaultVersionValue);
2561 if (warning == 0)
2562 hdlr->warning = NULL;
2563 else
2564 hdlr->warning = xmlParserWarning;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002565}
2566
2567/**
2568 * xmlDefaultSAXHandlerInit:
2569 *
2570 * Initialize the default SAX2 handler
2571 */
2572void
2573xmlDefaultSAXHandlerInit(void)
2574{
Daniel Veillard81273902003-09-30 00:43:48 +00002575#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard092643b2003-09-25 14:29:29 +00002576 xmlSAXVersion((xmlSAXHandlerPtr) &xmlDefaultSAXHandler, 1);
Daniel Veillard81273902003-09-30 00:43:48 +00002577#endif /* LIBXML_SAX1_ENABLED */
Daniel Veillard1af9a412003-08-20 22:54:39 +00002578}
2579
2580#ifdef LIBXML_HTML_ENABLED
2581
2582/**
2583 * xmlSAX2InitHtmlDefaultSAXHandler:
2584 * @hdlr: the SAX handler
2585 *
2586 * Initialize the default HTML SAX2 handler
2587 */
2588void
2589xmlSAX2InitHtmlDefaultSAXHandler(xmlSAXHandler *hdlr)
2590{
2591 if(hdlr->initialized != 0)
2592 return;
2593
2594 hdlr->internalSubset = xmlSAX2InternalSubset;
2595 hdlr->externalSubset = NULL;
2596 hdlr->isStandalone = NULL;
2597 hdlr->hasInternalSubset = NULL;
2598 hdlr->hasExternalSubset = NULL;
2599 hdlr->resolveEntity = NULL;
2600 hdlr->getEntity = xmlSAX2GetEntity;
2601 hdlr->getParameterEntity = NULL;
2602 hdlr->entityDecl = NULL;
2603 hdlr->attributeDecl = NULL;
2604 hdlr->elementDecl = NULL;
2605 hdlr->notationDecl = NULL;
2606 hdlr->unparsedEntityDecl = NULL;
2607 hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator;
2608 hdlr->startDocument = xmlSAX2StartDocument;
2609 hdlr->endDocument = xmlSAX2EndDocument;
2610 hdlr->startElement = xmlSAX2StartElement;
2611 hdlr->endElement = xmlSAX2EndElement;
2612 hdlr->reference = NULL;
2613 hdlr->characters = xmlSAX2Characters;
2614 hdlr->cdataBlock = xmlSAX2CDataBlock;
2615 hdlr->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
2616 hdlr->processingInstruction = NULL;
2617 hdlr->comment = xmlSAX2Comment;
2618 hdlr->warning = xmlParserWarning;
2619 hdlr->error = xmlParserError;
2620 hdlr->fatalError = xmlParserError;
2621
Daniel Veillard092643b2003-09-25 14:29:29 +00002622 hdlr->initialized = 1;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002623}
2624
2625/**
2626 * htmlDefaultSAXHandlerInit:
2627 *
2628 * Initialize the default SAX handler
2629 */
2630void
2631htmlDefaultSAXHandlerInit(void)
2632{
Daniel Veillard092643b2003-09-25 14:29:29 +00002633 xmlSAX2InitHtmlDefaultSAXHandler((xmlSAXHandlerPtr) &htmlDefaultSAXHandler);
Daniel Veillard1af9a412003-08-20 22:54:39 +00002634}
2635
2636#endif /* LIBXML_HTML_ENABLED */
2637
2638#ifdef LIBXML_DOCB_ENABLED
2639
2640/**
2641 * xmlSAX2InitDocbDefaultSAXHandler:
2642 * @hdlr: the SAX handler
2643 *
2644 * Initialize the default DocBook SAX2 handler
2645 */
2646void
2647xmlSAX2InitDocbDefaultSAXHandler(xmlSAXHandler *hdlr)
2648{
2649 if(hdlr->initialized != 0)
2650 return;
2651
2652 hdlr->internalSubset = xmlSAX2InternalSubset;
2653 hdlr->externalSubset = NULL;
2654 hdlr->isStandalone = xmlSAX2IsStandalone;
2655 hdlr->hasInternalSubset = xmlSAX2HasInternalSubset;
2656 hdlr->hasExternalSubset = xmlSAX2HasExternalSubset;
2657 hdlr->resolveEntity = xmlSAX2ResolveEntity;
2658 hdlr->getEntity = xmlSAX2GetEntity;
2659 hdlr->getParameterEntity = NULL;
2660 hdlr->entityDecl = xmlSAX2EntityDecl;
2661 hdlr->attributeDecl = NULL;
2662 hdlr->elementDecl = NULL;
2663 hdlr->notationDecl = NULL;
2664 hdlr->unparsedEntityDecl = NULL;
2665 hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator;
2666 hdlr->startDocument = xmlSAX2StartDocument;
2667 hdlr->endDocument = xmlSAX2EndDocument;
2668 hdlr->startElement = xmlSAX2StartElement;
2669 hdlr->endElement = xmlSAX2EndElement;
2670 hdlr->reference = xmlSAX2Reference;
2671 hdlr->characters = xmlSAX2Characters;
2672 hdlr->cdataBlock = NULL;
2673 hdlr->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
2674 hdlr->processingInstruction = NULL;
2675 hdlr->comment = xmlSAX2Comment;
2676 hdlr->warning = xmlParserWarning;
2677 hdlr->error = xmlParserError;
2678 hdlr->fatalError = xmlParserError;
2679
Daniel Veillardffbbed42003-10-10 14:46:54 +00002680 hdlr->initialized = 1;
Daniel Veillard1af9a412003-08-20 22:54:39 +00002681}
2682
2683/**
2684 * docbDefaultSAXHandlerInit:
2685 *
2686 * Initialize the default SAX handler
2687 */
2688void
2689docbDefaultSAXHandlerInit(void)
2690{
Daniel Veillard092643b2003-09-25 14:29:29 +00002691 xmlSAX2InitDocbDefaultSAXHandler((xmlSAXHandlerPtr) &docbDefaultSAXHandler);
Daniel Veillard1af9a412003-08-20 22:54:39 +00002692}
2693
2694#endif /* LIBXML_DOCB_ENABLED */