Newer
Older
/*
* SAX2.c : Default SAX2 handler to build a tree.
*
* See Copyright for the status of this software.
*
* Daniel Veillard <daniel@veillard.com>
*/
#define IN_LIBXML
#include "libxml.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <libxml/xmlmemory.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/valid.h>
#include <libxml/entities.h>
#include <libxml/xmlerror.h>
#include <libxml/debugXML.h>
#include <libxml/xmlIO.h>
#include <libxml/SAX.h>
#include <libxml/uri.h>
#include <libxml/valid.h>
#include <libxml/HTMLtree.h>
#include <libxml/globals.h>
/* Define SIZE_T_MAX unless defined through <limits.h>. */
#ifndef SIZE_T_MAX
# define SIZE_T_MAX ((size_t)-1)
#endif /* !SIZE_T_MAX */
/* #define DEBUG_SAX2 */
/* #define DEBUG_SAX2_TREE */
/**
* TODO:
*
* macro to flag unimplemented blocks
* XML_CATALOG_PREFER user env to select between system/public preferred
* option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
*> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
*> values "system" and "public". I have made the default be "system" to
*> match yours.
*/
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
/*
* xmlSAX2ErrMemory:
* @ctxt: an XML validation parser context
* @msg: a string to accompany the error message
*/
static void LIBXML_ATTR_FORMAT(2,0)
xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) {
xmlStructuredErrorFunc schannel = NULL;
const char *str1 = "out of memory\n";
if (ctxt != NULL) {
ctxt->errNo = XML_ERR_NO_MEMORY;
if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
schannel = ctxt->sax->serror;
__xmlRaiseError(schannel,
ctxt->vctxt.error, ctxt->vctxt.userData,
ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
XML_ERR_ERROR, NULL, 0, (const char *) str1,
NULL, NULL, 0, 0,
msg, (const char *) str1, NULL);
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
} else {
__xmlRaiseError(schannel,
NULL, NULL,
ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
XML_ERR_ERROR, NULL, 0, (const char *) str1,
NULL, NULL, 0, 0,
msg, (const char *) str1, NULL);
}
}
Daniel Veillard
committed
* xmlValidError:
* @ctxt: an XML validation parser context
* @error: the error number
* @msg: the error message
* @str1: extra data
* @str2: extra data
*
* Handle a validation error
*/
static void LIBXML_ATTR_FORMAT(3,0)
Daniel Veillard
committed
xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const char *str1, const char *str2)
{
xmlStructuredErrorFunc schannel = NULL;
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL) {
ctxt->errNo = error;
if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
schannel = ctxt->sax->serror;
__xmlRaiseError(schannel,
ctxt->vctxt.error, ctxt->vctxt.userData,
ctxt, NULL, XML_FROM_DTD, error,
XML_ERR_ERROR, NULL, 0, (const char *) str1,
(const char *) str2, NULL, 0, 0,
msg, (const char *) str1, (const char *) str2);
ctxt->valid = 0;
} else {
__xmlRaiseError(schannel,
NULL, NULL,
ctxt, NULL, XML_FROM_DTD, error,
XML_ERR_ERROR, NULL, 0, (const char *) str1,
(const char *) str2, NULL, 0, 0,
msg, (const char *) str1, (const char *) str2);
}
Daniel Veillard
committed
}
/**
* xmlFatalErrMsg:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @str1: an error string
* @str2: an error string
*
* Handle a fatal parser error, i.e. violating Well-Formedness constraints
*/
static void LIBXML_ATTR_FORMAT(3,0)
xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar *str1, const xmlChar *str2)
{
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL)
ctxt->errNo = error;
__xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
(const char *) str1, (const char *) str2,
NULL, 0, 0, msg, str1, str2);
if (ctxt != NULL) {
ctxt->wellFormed = 0;
ctxt->valid = 0;
if (ctxt->recovery == 0)
ctxt->disableSAX = 1;
}
}
/**
* xmlWarnMsg:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @str1: an error string
* @str2: an error string
*
* Handle a parser warning
*/
static void LIBXML_ATTR_FORMAT(3,0)
xmlWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar *str1)
{
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL)
ctxt->errNo = error;
__xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
(const char *) str1, NULL,
NULL, 0, 0, msg, str1);
}
/**
* xmlNsWarnMsg:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @str1: an error string
*
* Handle a namespace warning
*/
static void LIBXML_ATTR_FORMAT(3,0)
xmlNsWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar *str1, const xmlChar *str2)
{
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL)
ctxt->errNo = error;
__xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
(const char *) str1, (const char *) str2,
NULL, 0, 0, msg, str1, str2);
}
/**
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
* xmlSAX2GetPublicId:
* @ctx: the user data (XML parser context)
*
* Provides the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
*
* Returns a xmlChar *
*/
const xmlChar *
xmlSAX2GetPublicId(void *ctx ATTRIBUTE_UNUSED)
{
/* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
return(NULL);
}
/**
* xmlSAX2GetSystemId:
* @ctx: the user data (XML parser context)
*
* Provides the system ID, basically URL or filename e.g.
* http://www.sgmlsource.com/dtds/memo.dtd
*
* Returns a xmlChar *
*/
const xmlChar *
xmlSAX2GetSystemId(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->input == NULL)) return(NULL);
return((const xmlChar *) ctxt->input->filename);
}
/**
* xmlSAX2GetLineNumber:
* @ctx: the user data (XML parser context)
*
* Provide the line number of the current parsing point.
*
* Returns an int
*/
int
xmlSAX2GetLineNumber(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
return(ctxt->input->line);
}
/**
* xmlSAX2GetColumnNumber:
* @ctx: the user data (XML parser context)
*
* Provide the column number of the current parsing point.
*
* Returns an int
*/
int
xmlSAX2GetColumnNumber(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
return(ctxt->input->col);
}
/**
* xmlSAX2IsStandalone:
* @ctx: the user data (XML parser context)
*
* Is this document tagged standalone ?
*
* Returns 1 if true
*/
int
xmlSAX2IsStandalone(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->myDoc == NULL)) return(0);
return(ctxt->myDoc->standalone == 1);
}
/**
* xmlSAX2HasInternalSubset:
* @ctx: the user data (XML parser context)
*
* Does this document has an internal subset
*
* Returns 1 if true
*/
int
xmlSAX2HasInternalSubset(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
return(ctxt->myDoc->intSubset != NULL);
}
/**
* xmlSAX2HasExternalSubset:
* @ctx: the user data (XML parser context)
*
* Does this document has an external subset
*
* Returns 1 if true
*/
int
xmlSAX2HasExternalSubset(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
return(ctxt->myDoc->extSubset != NULL);
}
/**
* xmlSAX2InternalSubset:
* @ctx: the user data (XML parser context)
* @name: the root element name
* @ExternalID: the external ID
* @SystemID: the SYSTEM ID (e.g. filename or URL)
*
* Callback on internal subset declaration.
*/
void
xmlSAX2InternalSubset(void *ctx, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlDtdPtr dtd;
if (ctx == NULL) return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2InternalSubset(%s, %s, %s)\n",
name, ExternalID, SystemID);
#endif
if (ctxt->myDoc == NULL)
return;
dtd = xmlGetIntSubset(ctxt->myDoc);
if (dtd != NULL) {
if (ctxt->html)
return;
xmlUnlinkNode((xmlNodePtr) dtd);
xmlFreeDtd(dtd);
ctxt->myDoc->intSubset = NULL;
}
xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
if (ctxt->myDoc->intSubset == NULL)
xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset");
}
/**
* xmlSAX2ExternalSubset:
* @ctx: the user data (XML parser context)
* @name: the root element name
* @ExternalID: the external ID
* @SystemID: the SYSTEM ID (e.g. filename or URL)
*
* Callback on external subset declaration.
*/
void
xmlSAX2ExternalSubset(void *ctx, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if (ctx == NULL) return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2ExternalSubset(%s, %s, %s)\n",
name, ExternalID, SystemID);
#endif
if (((ExternalID != NULL) || (SystemID != NULL)) &&
(((ctxt->validate) || (ctxt->loadsubset != 0)) &&
(ctxt->wellFormed && ctxt->myDoc))) {
/*
* Try to fetch and parse the external subset.
*/
xmlParserInputPtr oldinput;
int oldinputNr;
int oldinputMax;
xmlParserInputPtr *oldinputTab;
xmlParserInputPtr input = NULL;
xmlCharEncoding enc;
int oldcharset;
const xmlChar *oldencoding;
/*
* Ask the Entity resolver to load the damn thing
*/
if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
SystemID);
if (input == NULL) {
return;
}
xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
/*
* make sure we won't destroy the main document context
*/
oldinput = ctxt->input;
oldinputNr = ctxt->inputNr;
oldinputMax = ctxt->inputMax;
oldinputTab = ctxt->inputTab;
oldcharset = ctxt->charset;
oldencoding = ctxt->encoding;
ctxt->encoding = NULL;
ctxt->inputTab = (xmlParserInputPtr *)
xmlMalloc(5 * sizeof(xmlParserInputPtr));
if (ctxt->inputTab == NULL) {
xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset");
ctxt->input = oldinput;
ctxt->inputNr = oldinputNr;
ctxt->inputMax = oldinputMax;
ctxt->inputTab = oldinputTab;
ctxt->charset = oldcharset;
ctxt->encoding = oldencoding;
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
return;
}
ctxt->inputNr = 0;
ctxt->inputMax = 5;
ctxt->input = NULL;
xmlPushInput(ctxt, input);
/*
* On the fly encoding conversion if needed
*/
if (ctxt->input->length >= 4) {
enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
xmlSwitchEncoding(ctxt, enc);
}
if (input->filename == NULL)
input->filename = (char *) xmlCanonicPath(SystemID);
input->line = 1;
input->col = 1;
input->base = ctxt->input->cur;
input->cur = ctxt->input->cur;
input->free = NULL;
/*
* let's parse that entity knowing it's an external subset.
*/
xmlParseExternalSubset(ctxt, ExternalID, SystemID);
/*
* Free up the external entities
*/
while (ctxt->inputNr > 1)
xmlPopInput(ctxt);
xmlFreeInputStream(ctxt->input);
xmlFree(ctxt->inputTab);
/*
* Restore the parsing context of the main entity
*/
ctxt->input = oldinput;
ctxt->inputNr = oldinputNr;
ctxt->inputMax = oldinputMax;
ctxt->inputTab = oldinputTab;
ctxt->charset = oldcharset;
if ((ctxt->encoding != NULL) &&
((ctxt->dict == NULL) ||
(!xmlDictOwns(ctxt->dict, ctxt->encoding))))
xmlFree((xmlChar *) ctxt->encoding);
ctxt->encoding = oldencoding;
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
/* ctxt->wellFormed = oldwellFormed; */
}
}
/**
* xmlSAX2ResolveEntity:
* @ctx: the user data (XML parser context)
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
*
* The entity loader, to control the loading of external entities,
* the application can either:
* - override this xmlSAX2ResolveEntity() callback in the SAX block
* - or better use the xmlSetExternalEntityLoader() function to
* set up it's own entity resolution routine
*
* Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
*/
xmlParserInputPtr
xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlParserInputPtr ret;
xmlChar *URI;
const char *base = NULL;
if (ctx == NULL) return(NULL);
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
if (ctxt->input != NULL)
base = ctxt->input->filename;
if (base == NULL)
base = ctxt->directory;
URI = xmlBuildURI(systemId, (const xmlChar *) base);
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2ResolveEntity(%s, %s)\n", publicId, systemId);
#endif
ret = xmlLoadExternalEntity((const char *) URI,
(const char *) publicId, ctxt);
if (URI != NULL)
xmlFree(URI);
return(ret);
}
/**
* xmlSAX2GetEntity:
* @ctx: the user data (XML parser context)
* @name: The entity name
*
* Get an entity by name
*
* Returns the xmlEntityPtr if found.
*/
xmlEntityPtr
xmlSAX2GetEntity(void *ctx, const xmlChar *name)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlEntityPtr ret = NULL;
if (ctx == NULL) return(NULL);
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2GetEntity(%s)\n", name);
#endif
if (ctxt->inSubset == 0) {
ret = xmlGetPredefinedEntity(name);
if (ret != NULL)
return(ret);
}
if ((ctxt->myDoc != NULL) && (ctxt->myDoc->standalone == 1)) {
if (ctxt->inSubset == 2) {
ctxt->myDoc->standalone = 0;
ret = xmlGetDocEntity(ctxt->myDoc, name);
ctxt->myDoc->standalone = 1;
} else {
ret = xmlGetDocEntity(ctxt->myDoc, name);
if (ret == NULL) {
ctxt->myDoc->standalone = 0;
ret = xmlGetDocEntity(ctxt->myDoc, name);
if (ret != NULL) {
xmlFatalErrMsg(ctxt, XML_ERR_NOT_STANDALONE,
"Entity(%s) document marked standalone but requires external subset\n",
name, NULL);
}
ctxt->myDoc->standalone = 1;
}
}
} else {
ret = xmlGetDocEntity(ctxt->myDoc, name);
}
return(ret);
}
/**
* xmlSAX2GetParameterEntity:
* @ctx: the user data (XML parser context)
* @name: The entity name
*
* Get a parameter entity by name
*
* Returns the xmlEntityPtr if found.
*/
xmlEntityPtr
xmlSAX2GetParameterEntity(void *ctx, const xmlChar *name)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlEntityPtr ret;
if (ctx == NULL) return(NULL);
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2GetParameterEntity(%s)\n", name);
#endif
ret = xmlGetParameterEntity(ctxt->myDoc, name);
return(ret);
}
/**
* xmlSAX2EntityDecl:
* @ctx: the user data (XML parser context)
* @name: the entity name
* @type: the entity type
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
* @content: the entity value (without processing).
*
* An entity definition has been parsed
*/
void
xmlSAX2EntityDecl(void *ctx, const xmlChar *name, int type,
const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
{
xmlEntityPtr ent;
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if (ctx == NULL) return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2EntityDecl(%s, %d, %s, %s, %s)\n",
name, type, publicId, systemId, content);
#endif
if (ctxt->inSubset == 1) {
ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
systemId, content);
if ((ent == NULL) && (ctxt->pedantic))
xmlWarnMsg(ctxt, XML_WAR_ENTITY_REDEFINED,
"Entity(%s) already defined in the internal subset\n",
name);
if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
xmlChar *URI;
const char *base = NULL;
if (ctxt->input != NULL)
base = ctxt->input->filename;
if (base == NULL)
base = ctxt->directory;
URI = xmlBuildURI(systemId, (const xmlChar *) base);
ent->URI = URI;
}
} else if (ctxt->inSubset == 2) {
ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
systemId, content);
if ((ent == NULL) && (ctxt->pedantic) &&
(ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
"Entity(%s) already defined in the external subset\n", name);
if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
xmlChar *URI;
const char *base = NULL;
if (ctxt->input != NULL)
base = ctxt->input->filename;
if (base == NULL)
base = ctxt->directory;
URI = xmlBuildURI(systemId, (const xmlChar *) base);
ent->URI = URI;
}
} else {
xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_PROCESSING,
"SAX.xmlSAX2EntityDecl(%s) called while not in subset\n",
name, NULL);
}
}
/**
* xmlSAX2AttributeDecl:
* @ctx: the user data (XML parser context)
* @elem: the name of the element
* @fullname: the attribute name
* @type: the attribute type
* @def: the type of default value
* @defaultValue: the attribute default value
* @tree: the tree of enumerated value set
*
* An attribute definition has been parsed
*/
void
xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
int type, int def, const xmlChar *defaultValue,
xmlEnumerationPtr tree)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlAttributePtr attr;
xmlChar *name = NULL, *prefix = NULL;
/* Avoid unused variable warning if features are disabled. */
(void) attr;
if ((ctxt == NULL) || (ctxt->myDoc == NULL))
return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2AttributeDecl(%s, %s, %d, %d, %s, ...)\n",
elem, fullname, type, def, defaultValue);
#endif
if ((xmlStrEqual(fullname, BAD_CAST "xml:id")) &&
(type != XML_ATTRIBUTE_ID)) {
/*
* Raise the error but keep the validity flag
*/
int tmp = ctxt->valid;
xmlErrValid(ctxt, XML_DTD_XMLID_TYPE,
"xml:id : attribute type should be ID\n", NULL, NULL);
ctxt->valid = tmp;
}
/* TODO: optimize name/prefix allocation */
name = xmlSplitQName(ctxt, fullname, &prefix);
ctxt->vctxt.valid = 1;
if (ctxt->inSubset == 1)
attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
name, prefix, (xmlAttributeType) type,
(xmlAttributeDefault) def, defaultValue, tree);
else if (ctxt->inSubset == 2)
attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
(xmlAttributeDefault) def, defaultValue, tree);
else {
xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
"SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n",
name, NULL);
xmlFreeEnumeration(tree);
return;
}
#ifdef LIBXML_VALID_ENABLED
if (ctxt->vctxt.valid == 0)
ctxt->valid = 0;
if ((attr != NULL) && (ctxt->validate) && (ctxt->wellFormed) &&
(ctxt->myDoc->intSubset != NULL))
ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
attr);
#endif /* LIBXML_VALID_ENABLED */
if (prefix != NULL)
xmlFree(prefix);
if (name != NULL)
xmlFree(name);
}
/**
* xmlSAX2ElementDecl:
* @ctx: the user data (XML parser context)
* @name: the element name
* @type: the element type
* @content: the element value tree
*
* An element definition has been parsed
*/
void
xmlSAX2ElementDecl(void *ctx, const xmlChar * name, int type,
xmlElementContentPtr content)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlElementPtr elem = NULL;
/* Avoid unused variable warning if features are disabled. */
(void) elem;
if ((ctxt == NULL) || (ctxt->myDoc == NULL))
return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2ElementDecl(%s, %d, ...)\n", name, type);
#endif
if (ctxt->inSubset == 1)
elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
name, (xmlElementTypeVal) type, content);
else if (ctxt->inSubset == 2)
elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
name, (xmlElementTypeVal) type, content);
else {
xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
"SAX.xmlSAX2ElementDecl(%s) called while not in subset\n",
name, NULL);
return;
}
#ifdef LIBXML_VALID_ENABLED
if (elem == NULL)
ctxt->valid = 0;
if (ctxt->validate && ctxt->wellFormed &&
ctxt->myDoc && ctxt->myDoc->intSubset)
ctxt->valid &=
xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
#endif /* LIBXML_VALID_ENABLED */
}
/**
* xmlSAX2NotationDecl:
* @ctx: the user data (XML parser context)
* @name: The name of the notation
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
*
* What to do when a notation declaration has been parsed.
*/
void
xmlSAX2NotationDecl(void *ctx, const xmlChar *name,
const xmlChar *publicId, const xmlChar *systemId)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlNotationPtr nota = NULL;
/* Avoid unused variable warning if features are disabled. */
(void) nota;
if ((ctxt == NULL) || (ctxt->myDoc == NULL))
return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2NotationDecl(%s, %s, %s)\n", name, publicId, systemId);
#endif
if ((publicId == NULL) && (systemId == NULL)) {
xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING,
"SAX.xmlSAX2NotationDecl(%s) externalID or PublicID missing\n",
name, NULL);
return;
} else if (ctxt->inSubset == 1)
nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
publicId, systemId);
else if (ctxt->inSubset == 2)
nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, name,
publicId, systemId);
else {
xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING,
"SAX.xmlSAX2NotationDecl(%s) called while not in subset\n",
name, NULL);
return;
}
#ifdef LIBXML_VALID_ENABLED
if (nota == NULL) ctxt->valid = 0;
if ((ctxt->validate) && (ctxt->wellFormed) &&
(ctxt->myDoc->intSubset != NULL))
ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
nota);
#endif /* LIBXML_VALID_ENABLED */
}
/**
* xmlSAX2UnparsedEntityDecl:
* @ctx: the user data (XML parser context)
* @name: The name of the entity
* @publicId: The public ID of the entity
* @systemId: The system ID of the entity
* @notationName: the name of the notation
*
* What to do when an unparsed entity declaration is parsed
*/
void
xmlSAX2UnparsedEntityDecl(void *ctx, const xmlChar *name,
const xmlChar *publicId, const xmlChar *systemId,
const xmlChar *notationName)
{
xmlEntityPtr ent;
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if (ctx == NULL) return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2UnparsedEntityDecl(%s, %s, %s, %s)\n",
name, publicId, systemId, notationName);
#endif
if (ctxt->inSubset == 1) {
ent = xmlAddDocEntity(ctxt->myDoc, name,
XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
publicId, systemId, notationName);
if ((ent == NULL) && (ctxt->pedantic) &&
(ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
"Entity(%s) already defined in the internal subset\n", name);
if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
xmlChar *URI;
const char *base = NULL;
if (ctxt->input != NULL)
base = ctxt->input->filename;
if (base == NULL)
base = ctxt->directory;
URI = xmlBuildURI(systemId, (const xmlChar *) base);
ent->URI = URI;
}
} else if (ctxt->inSubset == 2) {
ent = xmlAddDtdEntity(ctxt->myDoc, name,
XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
publicId, systemId, notationName);
if ((ent == NULL) && (ctxt->pedantic) &&
(ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
"Entity(%s) already defined in the external subset\n", name);
if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
xmlChar *URI;
const char *base = NULL;
if (ctxt->input != NULL)
base = ctxt->input->filename;
if (base == NULL)
base = ctxt->directory;
URI = xmlBuildURI(systemId, (const xmlChar *) base);
ent->URI = URI;
}
} else {
xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
"SAX.xmlSAX2UnparsedEntityDecl(%s) called while not in subset\n",
name, NULL);
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
}
}
/**
* xmlSAX2SetDocumentLocator:
* @ctx: the user data (XML parser context)
* @loc: A SAX Locator
*
* Receive the document locator at startup, actually xmlDefaultSAXLocator
* Everything is available on the context, so this is useless in our case.
*/
void
xmlSAX2SetDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
{
/* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2SetDocumentLocator()\n");
#endif
}
/**
* xmlSAX2StartDocument:
* @ctx: the user data (XML parser context)
*
* called when the document start being processed.
*/
void
xmlSAX2StartDocument(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlDocPtr doc;
if (ctx == NULL) return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2StartDocument()\n");
#endif
if (ctxt->html) {
#ifdef LIBXML_HTML_ENABLED
if (ctxt->myDoc == NULL)
ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
if (ctxt->myDoc == NULL) {
xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
return;
}
ctxt->myDoc->properties = XML_DOC_HTML;
ctxt->myDoc->parseFlags = ctxt->options;
#else
xmlGenericError(xmlGenericErrorContext,
"libxml2 built without HTML support\n");
ctxt->errNo = XML_ERR_INTERNAL_ERROR;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return;
#endif
} else {
doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
if (doc != NULL) {
doc->properties = 0;
if (ctxt->options & XML_PARSE_OLD10)
doc->properties |= XML_DOC_OLD10;
doc->parseFlags = ctxt->options;
if (ctxt->encoding != NULL)
doc->encoding = xmlStrdup(ctxt->encoding);
else
doc->encoding = NULL;
doc->standalone = ctxt->standalone;
} else {
xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
return;
}
if ((ctxt->dictNames) && (doc != NULL)) {
doc->dict = ctxt->dict;
xmlDictReference(doc->dict);
}
}
if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
(ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
ctxt->myDoc->URL = xmlPathToURI((const xmlChar *)ctxt->input->filename);
if (ctxt->myDoc->URL == NULL)
xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
}
}
/**
* xmlSAX2EndDocument:
* @ctx: the user data (XML parser context)
*
* called when the document end has been detected.