1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-10-27 04:55:04 +03:00
libxml2/xmlreader.c
Daniel Veillard e74d2e1cb8 augmented the XInclude API to be able to pass XML parser flags down to the
* xinclude.c xmllint.c xmlreader.c include/libxml/xinclude.h
  include/libxml/xmlerror.h: augmented the XInclude API
  to be able to pass XML parser flags down to the Inclusion
  process. Also resynchronized with the Last Call W3C Working
  Draft 10 November 2003 for the xpointer attribute.
* Makefile.am test/XInclude/docs/nodes[23].xml
  result/XInclude/*: augmented the tests for the new namespace and
  testing the xpointer attribute, changed the way error messages
  are tested
* doc/*: regenerated the documentation
Daniel
2003-12-09 11:35:37 +00:00

4793 lines
131 KiB
C

/*
* xmlreader.c: implements the xmlTextReader streaming node API
*
* NOTE:
* XmlTextReader.Normalization Property won't be supported, since
* it makes the parser non compliant to the XML recommendation
*
* See Copyright for the status of this software.
*
* daniel@veillard.com
*/
/*
* TODOs:
* - provide an API to preserve part of the tree
* - Streaming XInclude support
* - XML Schemas validation
* - setting(s) for NoBlanks
* - performances and tuning ...
*/
#define IN_LIBXML
#include "libxml.h"
#ifdef LIBXML_READER_ENABLED
#include <string.h> /* for memset() only ! */
#include <stdarg.h>
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <libxml/xmlmemory.h>
#include <libxml/xmlIO.h>
#include <libxml/xmlreader.h>
#include <libxml/parserInternals.h>
#include <libxml/relaxng.h>
#include <libxml/uri.h>
#ifdef LIBXML_XINCLUDE_ENABLED
#include <libxml/xinclude.h>
#endif
#ifdef LIBXML_PATTERN_ENABLED
#include <libxml/pattern.h>
#endif
/* #define DEBUG_CALLBACKS */
/* #define DEBUG_READER */
/**
* TODO:
*
* macro to flag unimplemented blocks
*/
#define TODO \
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
#ifdef DEBUG_READER
#define DUMP_READER xmlTextReaderDebug(reader);
#else
#define DUMP_READER
#endif
#define CHUNK_SIZE 512
/************************************************************************
* *
* The parser: maps the Text Reader API on top of the existing *
* parsing routines building a tree *
* *
************************************************************************/
#define XML_TEXTREADER_INPUT 1
#define XML_TEXTREADER_CTXT 2
typedef enum {
XML_TEXTREADER_MODE_INITIAL = 0,
XML_TEXTREADER_MODE_INTERACTIVE = 1,
XML_TEXTREADER_MODE_ERROR = 2,
XML_TEXTREADER_MODE_EOF =3,
XML_TEXTREADER_MODE_CLOSED = 4,
XML_TEXTREADER_MODE_READING = 5
} xmlTextReaderMode;
typedef enum {
XML_TEXTREADER_NONE = -1,
XML_TEXTREADER_START= 0,
XML_TEXTREADER_ELEMENT= 1,
XML_TEXTREADER_END= 2,
XML_TEXTREADER_EMPTY= 3,
XML_TEXTREADER_BACKTRACK= 4,
XML_TEXTREADER_DONE= 5,
XML_TEXTREADER_ERROR= 6
} xmlTextReaderState;
typedef enum {
XML_TEXTREADER_NOT_VALIDATE = 0,
XML_TEXTREADER_VALIDATE_DTD = 1,
XML_TEXTREADER_VALIDATE_RNG = 2
} xmlTextReaderValidate;
struct _xmlTextReader {
int mode; /* the parsing mode */
xmlDocPtr doc; /* when walking an existing doc */
xmlTextReaderValidate validate;/* is there any validation */
int allocs; /* what structure were deallocated */
xmlTextReaderState state;
xmlParserCtxtPtr ctxt; /* the parser context */
xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
xmlParserInputBufferPtr input; /* the input */
startElementSAXFunc startElement;/* initial SAX callbacks */
endElementSAXFunc endElement; /* idem */
startElementNsSAX2Func startElementNs;/* idem */
endElementNsSAX2Func endElementNs; /* idem */
charactersSAXFunc characters;
cdataBlockSAXFunc cdataBlock;
unsigned int base; /* base of the segment in the input */
unsigned int cur; /* current position in the input */
xmlNodePtr node; /* current node */
xmlNodePtr curnode;/* current attribute node */
int depth; /* depth of the current node */
xmlNodePtr faketext;/* fake xmlNs chld */
int preserve;/* preserve the resulting document */
xmlBufferPtr buffer; /* used to return const xmlChar * */
xmlDictPtr dict; /* the context dictionnary */
/* entity stack when traversing entities content */
xmlNodePtr ent; /* Current Entity Ref Node */
int entNr; /* Depth of the entities stack */
int entMax; /* Max depth of the entities stack */
xmlNodePtr *entTab; /* array of entities */
/* error handling */
xmlTextReaderErrorFunc errorFunc; /* callback function */
void *errorFuncArg; /* callback function user argument */
#ifdef LIBXML_SCHEMAS_ENABLED
/* Handling of RelaxNG validation */
xmlRelaxNGPtr rngSchemas; /* The Relax NG schemas */
xmlRelaxNGValidCtxtPtr rngValidCtxt;/* The Relax NG validation context */
int rngValidErrors;/* The number of errors detected */
xmlNodePtr rngFullNode; /* the node if RNG not progressive */
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
/* Handling of XInclude processing */
int xinclude; /* is xinclude asked for */
const xmlChar * xinclude_name; /* the xinclude name from dict */
xmlXIncludeCtxtPtr xincctxt; /* the xinclude context */
int in_xinclude; /* counts for xinclude */
#endif
#ifdef LIBXML_PATTERN_ENABLED
int patternNr; /* number of preserve patterns */
int patternMax; /* max preserve patterns */
xmlPatternPtr *patternTab; /* array of preserve patterns */
#endif
int preserves; /* level of preserves */
int parserFlags; /* the set of options set */
};
#define NODE_IS_EMPTY 0x1
#define NODE_IS_PRESERVED 0x2
#define NODE_IS_SPRESERVED 0x4
/**
* CONSTSTR:
*
* Macro used to return an interned string
*/
#define CONSTSTR(str) xmlDictLookup(reader->dict, (str), -1)
#define CONSTQSTR(p, str) xmlDictQLookup(reader->dict, (p), (str))
static int xmlTextReaderReadTree(xmlTextReaderPtr reader);
static int xmlTextReaderNextTree(xmlTextReaderPtr reader);
/************************************************************************
* *
* Our own version of the freeing routines as we recycle nodes *
* *
************************************************************************/
/**
* DICT_FREE:
* @str: a string
*
* Free a string if it is not owned by the "dict" dictionnary in the
* current scope
*/
#define DICT_FREE(str) \
if ((str) && ((!dict) || \
(xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
xmlFree((char *)(str));
static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
/**
* xmlFreeID:
* @not: A id
*
* Deallocate the memory used by an id definition
*/
static void
xmlFreeID(xmlIDPtr id) {
xmlDictPtr dict = NULL;
if (id == NULL) return;
if (id->doc != NULL)
dict = id->doc->dict;
if (id->value != NULL)
DICT_FREE(id->value)
xmlFree(id);
}
/**
* xmlTextReaderRemoveID:
* @doc: the document
* @attr: the attribute
*
* Remove the given attribute from the ID table maintained internally.
*
* Returns -1 if the lookup failed and 0 otherwise
*/
static int
xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
xmlIDTablePtr table;
xmlIDPtr id;
xmlChar *ID;
if (doc == NULL) return(-1);
if (attr == NULL) return(-1);
table = (xmlIDTablePtr) doc->ids;
if (table == NULL)
return(-1);
if (attr == NULL)
return(-1);
ID = xmlNodeListGetString(doc, attr->children, 1);
if (ID == NULL)
return(-1);
id = xmlHashLookup(table, ID);
xmlFree(ID);
if (id == NULL || id->attr != attr) {
return(-1);
}
id->name = attr->name;
id->attr = NULL;
return(0);
}
/**
* xmlTextReaderFreeProp:
* @reader: the xmlTextReaderPtr used
* @cur: the node
*
* Free a node.
*/
static void
xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
xmlDictPtr dict;
dict = reader->ctxt->dict;
if (cur == NULL) return;
/* Check for ID removal -> leading to invalid references ! */
if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
((cur->parent->doc->intSubset != NULL) ||
(cur->parent->doc->extSubset != NULL))) {
if (xmlIsID(cur->parent->doc, cur->parent, cur))
xmlTextReaderRemoveID(cur->parent->doc, cur);
}
if (cur->children != NULL)
xmlTextReaderFreeNodeList(reader, cur->children);
DICT_FREE(cur->name);
if ((reader != NULL) && (reader->ctxt != NULL) &&
(reader->ctxt->freeAttrsNr < 100)) {
cur->next = reader->ctxt->freeAttrs;
reader->ctxt->freeAttrs = cur;
reader->ctxt->freeAttrsNr++;
} else {
xmlFree(cur);
}
}
/**
* xmlTextReaderFreePropList:
* @reader: the xmlTextReaderPtr used
* @cur: the first property in the list
*
* Free a property and all its siblings, all the children are freed too.
*/
static void
xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
xmlAttrPtr next;
if (cur == NULL) return;
while (cur != NULL) {
next = cur->next;
xmlTextReaderFreeProp(reader, cur);
cur = next;
}
}
/**
* xmlTextReaderFreeNodeList:
* @reader: the xmlTextReaderPtr used
* @cur: the first node in the list
*
* Free a node and all its siblings, this is a recursive behaviour, all
* the children are freed too.
*/
static void
xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
xmlNodePtr next;
xmlDictPtr dict;
dict = reader->ctxt->dict;
if (cur == NULL) return;
if (cur->type == XML_NAMESPACE_DECL) {
xmlFreeNsList((xmlNsPtr) cur);
return;
}
if ((cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
xmlFreeDoc((xmlDocPtr) cur);
return;
}
while (cur != NULL) {
next = cur->next;
/* unroll to speed up freeing the document */
if (cur->type != XML_DTD_NODE) {
if ((cur->children != NULL) &&
(cur->type != XML_ENTITY_REF_NODE)) {
if (cur->children->parent == cur)
xmlTextReaderFreeNodeList(reader, cur->children);
cur->children = NULL;
}
if (((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_XINCLUDE_START) ||
(cur->type == XML_XINCLUDE_END)) &&
(cur->properties != NULL))
xmlTextReaderFreePropList(reader, cur->properties);
if ((cur->type != XML_ELEMENT_NODE) &&
(cur->type != XML_XINCLUDE_START) &&
(cur->type != XML_XINCLUDE_END) &&
(cur->type != XML_ENTITY_REF_NODE)) {
DICT_FREE(cur->content);
}
if (((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_XINCLUDE_START) ||
(cur->type == XML_XINCLUDE_END)) &&
(cur->nsDef != NULL))
xmlFreeNsList(cur->nsDef);
/*
* we don't free element names here they are interned now
*/
if ((cur->type != XML_TEXT_NODE) &&
(cur->type != XML_COMMENT_NODE))
DICT_FREE(cur->name);
if (((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_TEXT_NODE)) &&
(reader != NULL) && (reader->ctxt != NULL) &&
(reader->ctxt->freeElemsNr < 100)) {
cur->next = reader->ctxt->freeElems;
reader->ctxt->freeElems = cur;
reader->ctxt->freeElemsNr++;
} else {
xmlFree(cur);
}
}
cur = next;
}
}
/**
* xmlTextReaderFreeNode:
* @reader: the xmlTextReaderPtr used
* @cur: the node
*
* Free a node, this is a recursive behaviour, all the children are freed too.
* This doesn't unlink the child from the list, use xmlUnlinkNode() first.
*/
static void
xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) {
xmlDictPtr dict;
dict = reader->ctxt->dict;
if (cur->type == XML_DTD_NODE) {
xmlFreeDtd((xmlDtdPtr) cur);
return;
}
if (cur->type == XML_NAMESPACE_DECL) {
xmlFreeNs((xmlNsPtr) cur);
return;
}
if (cur->type == XML_ATTRIBUTE_NODE) {
xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur);
return;
}
if ((cur->children != NULL) &&
(cur->type != XML_ENTITY_REF_NODE)) {
if (cur->children->parent == cur)
xmlTextReaderFreeNodeList(reader, cur->children);
cur->children = NULL;
}
if (((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_XINCLUDE_START) ||
(cur->type == XML_XINCLUDE_END)) &&
(cur->properties != NULL))
xmlTextReaderFreePropList(reader, cur->properties);
if ((cur->type != XML_ELEMENT_NODE) &&
(cur->type != XML_XINCLUDE_START) &&
(cur->type != XML_XINCLUDE_END) &&
(cur->type != XML_ENTITY_REF_NODE)) {
DICT_FREE(cur->content);
}
if (((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_XINCLUDE_START) ||
(cur->type == XML_XINCLUDE_END)) &&
(cur->nsDef != NULL))
xmlFreeNsList(cur->nsDef);
/*
* we don't free names here they are interned now
*/
if ((cur->type != XML_TEXT_NODE) &&
(cur->type != XML_COMMENT_NODE))
DICT_FREE(cur->name);
if (((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_TEXT_NODE)) &&
(reader != NULL) && (reader->ctxt != NULL) &&
(reader->ctxt->freeElemsNr < 100)) {
cur->next = reader->ctxt->freeElems;
reader->ctxt->freeElems = cur;
reader->ctxt->freeElemsNr++;
} else {
xmlFree(cur);
}
}
/**
* xmlTextReaderFreeIDTable:
* @table: An id table
*
* Deallocate the memory used by an ID hash table.
*/
static void
xmlTextReaderFreeIDTable(xmlIDTablePtr table) {
xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
}
/**
* xmlTextReaderFreeDoc:
* @reader: the xmlTextReaderPtr used
* @cur: pointer to the document
*
* Free up all the structures used by a document, tree included.
*/
static void
xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) {
xmlDtdPtr extSubset, intSubset;
if (cur == NULL) return;
/*
* Do this before freeing the children list to avoid ID lookups
*/
if (cur->ids != NULL) xmlTextReaderFreeIDTable((xmlIDTablePtr) cur->ids);
cur->ids = NULL;
if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
cur->refs = NULL;
extSubset = cur->extSubset;
intSubset = cur->intSubset;
if (intSubset == extSubset)
extSubset = NULL;
if (extSubset != NULL) {
xmlUnlinkNode((xmlNodePtr) cur->extSubset);
cur->extSubset = NULL;
xmlFreeDtd(extSubset);
}
if (intSubset != NULL) {
xmlUnlinkNode((xmlNodePtr) cur->intSubset);
cur->intSubset = NULL;
xmlFreeDtd(intSubset);
}
if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);
if (cur->version != NULL) xmlFree((char *) cur->version);
if (cur->name != NULL) xmlFree((char *) cur->name);
if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
if (cur->URL != NULL) xmlFree((char *) cur->URL);
xmlFree(cur);
}
/************************************************************************
* *
* The reader core parser *
* *
************************************************************************/
#ifdef DEBUG_READER
static void
xmlTextReaderDebug(xmlTextReaderPtr reader) {
if ((reader == NULL) || (reader->ctxt == NULL)) {
fprintf(stderr, "xmlTextReader NULL\n");
return;
}
fprintf(stderr, "xmlTextReader: state %d depth %d ",
reader->state, reader->depth);
if (reader->node == NULL) {
fprintf(stderr, "node = NULL\n");
} else {
fprintf(stderr, "node %s\n", reader->node->name);
}
fprintf(stderr, " input: base %d, cur %d, depth %d: ",
reader->base, reader->cur, reader->ctxt->nodeNr);
if (reader->input->buffer == NULL) {
fprintf(stderr, "buffer is NULL\n");
} else {
#ifdef LIBXML_DEBUG_ENABLED
xmlDebugDumpString(stderr,
&reader->input->buffer->content[reader->cur]);
#endif
fprintf(stderr, "\n");
}
}
#endif
/**
* xmlTextReaderEntPush:
* @reader: the xmlTextReaderPtr used
* @value: the entity reference node
*
* Pushes a new entity reference node on top of the entities stack
*
* Returns 0 in case of error, the index in the stack otherwise
*/
static int
xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
{
if (reader->entMax <= 0) {
reader->entMax = 10;
reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
sizeof(reader->entTab[0]));
if (reader->entTab == NULL) {
xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
return (0);
}
}
if (reader->entNr >= reader->entMax) {
reader->entMax *= 2;
reader->entTab =
(xmlNodePtr *) xmlRealloc(reader->entTab,
reader->entMax *
sizeof(reader->entTab[0]));
if (reader->entTab == NULL) {
xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
return (0);
}
}
reader->entTab[reader->entNr] = value;
reader->ent = value;
return (reader->entNr++);
}
/**
* xmlTextReaderEntPop:
* @reader: the xmlTextReaderPtr used
*
* Pops the top element entity from the entities stack
*
* Returns the entity just removed
*/
static xmlNodePtr
xmlTextReaderEntPop(xmlTextReaderPtr reader)
{
xmlNodePtr ret;
if (reader->entNr <= 0)
return (0);
reader->entNr--;
if (reader->entNr > 0)
reader->ent = reader->entTab[reader->entNr - 1];
else
reader->ent = NULL;
ret = reader->entTab[reader->entNr];
reader->entTab[reader->entNr] = 0;
return (ret);
}
/**
* xmlTextReaderStartElement:
* @ctx: the user data (XML parser context)
* @fullname: The element name, including namespace prefix
* @atts: An array of name/value attributes pairs, NULL terminated
*
* called when an opening tag has been processed.
*/
static void
xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
const xmlChar **atts) {
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlTextReaderPtr reader = ctxt->_private;
#ifdef DEBUG_CALLBACKS
printf("xmlTextReaderStartElement(%s)\n", fullname);
#endif
if ((reader != NULL) && (reader->startElement != NULL)) {
reader->startElement(ctx, fullname, atts);
if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
(ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
(ctxt->input->cur[1] == '>'))
ctxt->node->extra = NODE_IS_EMPTY;
}
if (reader != NULL)
reader->state = XML_TEXTREADER_ELEMENT;
}
/**
* xmlTextReaderEndElement:
* @ctx: the user data (XML parser context)
* @fullname: The element name, including namespace prefix
*
* called when an ending tag has been processed.
*/
static void
xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlTextReaderPtr reader = ctxt->_private;
#ifdef DEBUG_CALLBACKS
printf("xmlTextReaderEndElement(%s)\n", fullname);
#endif
if ((reader != NULL) && (reader->endElement != NULL)) {
reader->endElement(ctx, fullname);
}
}
/**
* xmlTextReaderStartElementNs:
* @ctx: the user data (XML parser context)
* @localname: the local name of the element
* @prefix: the element namespace prefix if available
* @URI: the element namespace name if available
* @nb_namespaces: number of namespace definitions on that node
* @namespaces: pointer to the array of prefix/URI pairs namespace definitions
* @nb_attributes: the number of attributes on that node
* nb_defaulted: the number of defaulted attributes.
* @attributes: pointer to the array of (localname/prefix/URI/value/end)
* attribute values.
*
* called when an opening tag has been processed.
*/
static void
xmlTextReaderStartElementNs(void *ctx,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int nb_defaulted,
const xmlChar **attributes)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlTextReaderPtr reader = ctxt->_private;
#ifdef DEBUG_CALLBACKS
printf("xmlTextReaderStartElementNs(%s)\n", localname);
#endif
if ((reader != NULL) && (reader->startElementNs != NULL)) {
reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces,
namespaces, nb_attributes, nb_defaulted,
attributes);
if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
(ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
(ctxt->input->cur[1] == '>'))
ctxt->node->extra = NODE_IS_EMPTY;
}
if (reader != NULL)
reader->state = XML_TEXTREADER_ELEMENT;
}
/**
* xmlTextReaderEndElementNs:
* @ctx: the user data (XML parser context)
* @localname: the local name of the element
* @prefix: the element namespace prefix if available
* @URI: the element namespace name if available
*
* called when an ending tag has been processed.
*/
static void
xmlTextReaderEndElementNs(void *ctx,
const xmlChar * localname,
const xmlChar * prefix,
const xmlChar * URI)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlTextReaderPtr reader = ctxt->_private;
#ifdef DEBUG_CALLBACKS
printf("xmlTextReaderEndElementNs(%s)\n", localname);
#endif
if ((reader != NULL) && (reader->endElementNs != NULL)) {
reader->endElementNs(ctx, localname, prefix, URI);
}
}
/**
* xmlTextReaderCharacters:
* @ctx: the user data (XML parser context)
* @ch: a xmlChar string
* @len: the number of xmlChar
*
* receiving some chars from the parser.
*/
static void
xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlTextReaderPtr reader = ctxt->_private;
#ifdef DEBUG_CALLBACKS
printf("xmlTextReaderCharacters()\n");
#endif
if ((reader != NULL) && (reader->characters != NULL)) {
reader->characters(ctx, ch, len);
}
}
/**
* xmlTextReaderCDataBlock:
* @ctx: the user data (XML parser context)
* @value: The pcdata content
* @len: the block length
*
* called when a pcdata block has been parsed
*/
static void
xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlTextReaderPtr reader = ctxt->_private;
#ifdef DEBUG_CALLBACKS
printf("xmlTextReaderCDataBlock()\n");
#endif
if ((reader != NULL) && (reader->cdataBlock != NULL)) {
reader->cdataBlock(ctx, ch, len);
}
}
/**
* xmlTextReaderPushData:
* @reader: the xmlTextReaderPtr used
*
* Push data down the progressive parser until a significant callback
* got raised.
*
* Returns -1 in case of failure, 0 otherwise
*/
static int
xmlTextReaderPushData(xmlTextReaderPtr reader) {
xmlBufferPtr inbuf;
int val, s;
xmlTextReaderState oldstate;
if ((reader->input == NULL) || (reader->input->buffer == NULL))
return(-1);
oldstate = reader->state;
reader->state = XML_TEXTREADER_NONE;
inbuf = reader->input->buffer;
while (reader->state == XML_TEXTREADER_NONE) {
if (inbuf->use < reader->cur + CHUNK_SIZE) {
/*
* Refill the buffer unless we are at the end of the stream
*/
if (reader->mode != XML_TEXTREADER_MODE_EOF) {
val = xmlParserInputBufferRead(reader->input, 4096);
if ((val == 0) &&
(inbuf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) {
if (inbuf->use == reader->cur) {
reader->mode = XML_TEXTREADER_MODE_EOF;
reader->state = oldstate;
if ((oldstate != XML_TEXTREADER_START) ||
(reader->ctxt->myDoc != NULL))
return(val);
}
} else if (val < 0) {
reader->mode = XML_TEXTREADER_MODE_EOF;
reader->state = oldstate;
if ((oldstate != XML_TEXTREADER_START) ||
(reader->ctxt->myDoc != NULL))
return(val);
} else if (val == 0) {
/* mark the end of the stream and process the remains */
reader->mode = XML_TEXTREADER_MODE_EOF;
break;
}
} else
break;
}
/*
* parse by block of CHUNK_SIZE bytes, various tests show that
* it's the best tradeoff at least on a 1.2GH Duron
*/
if (inbuf->use >= reader->cur + CHUNK_SIZE) {
val = xmlParseChunk(reader->ctxt,
(const char *) &inbuf->content[reader->cur],
CHUNK_SIZE, 0);
reader->cur += CHUNK_SIZE;
if ((val != 0) && (reader->ctxt->wellFormed == 0))
return(-1);
} else {
s = inbuf->use - reader->cur;
val = xmlParseChunk(reader->ctxt,
(const char *) &inbuf->content[reader->cur],
s, 0);
reader->cur += s;
if ((val != 0) && (reader->ctxt->wellFormed == 0))
return(-1);
break;
}
}
/*
* Discard the consumed input when needed and possible
*/
if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
if ((reader->cur >= 4096) &&
(inbuf->use - reader->cur <= CHUNK_SIZE)) {
val = xmlBufferShrink(inbuf, reader->cur);
if (val >= 0) {
reader->cur -= val;
}
}
}
/*
* At the end of the stream signal that the work is done to the Push
* parser.
*/
else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
if (reader->mode != XML_TEXTREADER_DONE) {
s = inbuf->use - reader->cur;
val = xmlParseChunk(reader->ctxt,
(const char *) &inbuf->content[reader->cur],
s, 1);
reader->cur = inbuf->use;
reader->mode = XML_TEXTREADER_DONE;
if ((val != 0) && (reader->ctxt->wellFormed == 0))
return(-1);
}
}
reader->state = oldstate;
return(0);
}
#ifdef LIBXML_REGEXP_ENABLED
/**
* xmlTextReaderValidatePush:
* @reader: the xmlTextReaderPtr used
*
* Push the current node for validation
*/
static void
xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
xmlNodePtr node = reader->node;
if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
(reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
reader->ctxt->myDoc, node, node->name);
} else {
/* TODO use the BuildQName interface */
xmlChar *qname;
qname = xmlStrdup(node->ns->prefix);
qname = xmlStrcat(qname, BAD_CAST ":");
qname = xmlStrcat(qname, node->name);
reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
reader->ctxt->myDoc, node, qname);
if (qname != NULL)
xmlFree(qname);
}
#ifdef LIBXML_SCHEMAS_ENABLED
} else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
(reader->rngValidCtxt != NULL)) {
int ret;
if (reader->rngFullNode != NULL) return;
ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
reader->ctxt->myDoc,
node);
if (ret == 0) {
/*
* this element requires a full tree
*/
node = xmlTextReaderExpand(reader);
if (node == NULL) {
printf("Expand failed !\n");
ret = -1;
} else {
ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
reader->ctxt->myDoc,
node);
reader->rngFullNode = node;
}
}
if (ret != 1)
reader->rngValidErrors++;
#endif
}
}
/**
* xmlTextReaderValidateCData:
* @reader: the xmlTextReaderPtr used
* @data: pointer to the CData
* @len: lenght of the CData block in bytes.
*
* Push some CData for validation
*/
static void
xmlTextReaderValidateCData(xmlTextReaderPtr reader,
const xmlChar *data, int len) {
if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
(reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
data, len);
#ifdef LIBXML_SCHEMAS_ENABLED
} else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
(reader->rngValidCtxt != NULL)) {
int ret;
if (reader->rngFullNode != NULL) return;
ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
if (ret != 1)
reader->rngValidErrors++;
#endif
}
}
/**
* xmlTextReaderValidatePop:
* @reader: the xmlTextReaderPtr used
*
* Pop the current node from validation
*/
static void
xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
xmlNodePtr node = reader->node;
if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
(reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
reader->ctxt->myDoc, node, node->name);
} else {
/* TODO use the BuildQName interface */
xmlChar *qname;
qname = xmlStrdup(node->ns->prefix);
qname = xmlStrcat(qname, BAD_CAST ":");
qname = xmlStrcat(qname, node->name);
reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
reader->ctxt->myDoc, node, qname);
if (qname != NULL)
xmlFree(qname);
}
#ifdef LIBXML_SCHEMAS_ENABLED
} else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
(reader->rngValidCtxt != NULL)) {
int ret;
if (reader->rngFullNode != NULL) {
if (node == reader->rngFullNode)
reader->rngFullNode = NULL;
return;
}
ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
reader->ctxt->myDoc,
node);
if (ret != 1)
reader->rngValidErrors++;
#endif
}
}
/**
* xmlTextReaderValidateEntity:
* @reader: the xmlTextReaderPtr used
*
* Handle the validation when an entity reference is encountered and
* entity substitution is not activated. As a result the parser interface
* must walk through the entity and do the validation calls
*/
static void
xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
xmlNodePtr oldnode = reader->node;
xmlNodePtr node = reader->node;
xmlParserCtxtPtr ctxt = reader->ctxt;
do {
if (node->type == XML_ENTITY_REF_NODE) {
/*
* Case where the underlying tree is not availble, lookup the entity
* and walk it.
*/
if ((node->children == NULL) && (ctxt->sax != NULL) &&
(ctxt->sax->getEntity != NULL)) {
node->children = (xmlNodePtr)
ctxt->sax->getEntity(ctxt, node->name);
}
if ((node->children != NULL) &&
(node->children->type == XML_ENTITY_DECL) &&
(node->children->children != NULL)) {
xmlTextReaderEntPush(reader, node);
node = node->children->children;
continue;
} else {
/*
* The error has probably be raised already.
*/
if (node == oldnode)
break;
node = node->next;
}
#ifdef LIBXML_REGEXP_ENABLED
} else if (node->type == XML_ELEMENT_NODE) {
reader->node = node;
xmlTextReaderValidatePush(reader);
} else if ((node->type == XML_TEXT_NODE) ||
(node->type == XML_CDATA_SECTION_NODE)) {
xmlTextReaderValidateCData(reader, node->content,
xmlStrlen(node->content));
#endif
}
/*
* go to next node
*/
if (node->children != NULL) {
node = node->children;
continue;
} else if (node->type == XML_ELEMENT_NODE) {
xmlTextReaderValidatePop(reader);
}
if (node->next != NULL) {
node = node->next;
continue;
}
do {
node = node->parent;
if (node->type == XML_ELEMENT_NODE) {
xmlNodePtr tmp;
if (reader->entNr == 0) {
while ((tmp = node->last) != NULL) {
if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
xmlUnlinkNode(tmp);
xmlTextReaderFreeNode(reader, tmp);
} else
break;
}
}
reader->node = node;
xmlTextReaderValidatePop(reader);
}
if ((node->type == XML_ENTITY_DECL) &&
(reader->ent != NULL) && (reader->ent->children == node)) {
node = xmlTextReaderEntPop(reader);
}
if (node == oldnode)
break;
if (node->next != NULL) {
node = node->next;
break;
}
} while ((node != NULL) && (node != oldnode));
} while ((node != NULL) && (node != oldnode));
reader->node = oldnode;
}
#endif /* LIBXML_REGEXP_ENABLED */
/**
* xmlTextReaderGetSuccessor:
* @cur: the current node
*
* Get the successor of a node if available.
*
* Returns the successor node or NULL
*/
static xmlNodePtr
xmlTextReaderGetSuccessor(xmlNodePtr cur) {
if (cur == NULL) return(NULL) ; /* ERROR */
if (cur->next != NULL) return(cur->next) ;
do {
cur = cur->parent;
if (cur == NULL) return(NULL);
if (cur->next != NULL) return(cur->next);
} while (cur != NULL);
return(cur);
}
/**
* xmlTextReaderDoExpand:
* @reader: the xmlTextReaderPtr used
*
* Makes sure that the current node is fully read as well as all its
* descendant. It means the full DOM subtree must be available at the
* end of the call.
*
* Returns 1 if the node was expanded successfully, 0 if there is no more
* nodes to read, or -1 in case of error
*/
static int
xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
int val;
if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
return(-1);
do {
if (reader->ctxt->instate == XML_PARSER_EOF) return(1);
if (xmlTextReaderGetSuccessor(reader->node) != NULL)
return(1);
if (reader->ctxt->nodeNr < reader->depth)
return(1);
if (reader->mode == XML_TEXTREADER_MODE_EOF)
return(1);
val = xmlTextReaderPushData(reader);
if (val < 0)
return(-1);
} while(reader->mode != XML_TEXTREADER_MODE_EOF);
return(1);
}
/**
* xmlTextReaderRead:
* @reader: the xmlTextReaderPtr used
*
* Moves the position of the current instance to the next node in
* the stream, exposing its properties.
*
* Returns 1 if the node was read successfully, 0 if there is no more
* nodes to read, or -1 in case of error
*/
int
xmlTextReaderRead(xmlTextReaderPtr reader) {
int val, olddepth = 0;
xmlTextReaderState oldstate = XML_TEXTREADER_START;
xmlNodePtr oldnode = NULL;
if (reader == NULL)
return(-1);
if (reader->doc != NULL)
return(xmlTextReaderReadTree(reader));
if (reader->ctxt == NULL)
return(-1);
if (reader->ctxt->wellFormed != 1)
return(-1);
#ifdef DEBUG_READER
fprintf(stderr, "\nREAD ");
DUMP_READER
#endif
reader->curnode = NULL;
if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
/*
* Initial state
*/
do {
val = xmlTextReaderPushData(reader);
if (val < 0)
return(-1);
} while ((reader->ctxt->node == NULL) &&
((reader->mode != XML_TEXTREADER_MODE_EOF) &&
(reader->mode != XML_TEXTREADER_DONE)));
if (reader->ctxt->node == NULL) {
if (reader->ctxt->myDoc != NULL) {
reader->node = reader->ctxt->myDoc->children;
}
if (reader->node == NULL)
return(-1);
reader->state = XML_TEXTREADER_ELEMENT;
} else {
if (reader->ctxt->myDoc != NULL) {
reader->node = reader->ctxt->myDoc->children;
}
if (reader->node == NULL)
reader->node = reader->ctxt->nodeTab[0];
reader->state = XML_TEXTREADER_ELEMENT;
}
reader->depth = 0;
goto node_found;
}
oldstate = reader->state;
olddepth = reader->ctxt->nodeNr;
oldnode = reader->node;
get_next_node:
/*
* If we are not backtracking on ancestors or examined nodes,
* that the parser didn't finished or that we arent at the end
* of stream, continue processing.
*/
while ((reader->node->next == NULL) &&
(reader->ctxt->nodeNr == olddepth) &&
((oldstate == XML_TEXTREADER_BACKTRACK) ||
(reader->node->children == NULL) ||
(reader->node->type == XML_ENTITY_REF_NODE) ||
((reader->node->children != NULL) &&
(reader->node->children->type == XML_TEXT_NODE) &&
(reader->node->children->next == NULL)) ||
(reader->node->type == XML_DTD_NODE) ||
(reader->node->type == XML_DOCUMENT_NODE) ||
(reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
((reader->ctxt->node == NULL) ||
(reader->ctxt->node == reader->node) ||
(reader->ctxt->node == reader->node->parent)) &&
(reader->ctxt->instate != XML_PARSER_EOF)) {
val = xmlTextReaderPushData(reader);
if (val < 0)
return(-1);
if (reader->node == NULL)
goto node_end;
}
if (oldstate != XML_TEXTREADER_BACKTRACK) {
if ((reader->node->children != NULL) &&
(reader->node->type != XML_ENTITY_REF_NODE) &&
(reader->node->type != XML_XINCLUDE_START) &&
(reader->node->type != XML_DTD_NODE)) {
reader->node = reader->node->children;
reader->depth++;
reader->state = XML_TEXTREADER_ELEMENT;
goto node_found;
}
}
if (reader->node->next != NULL) {
if ((oldstate == XML_TEXTREADER_ELEMENT) &&
(reader->node->type == XML_ELEMENT_NODE) &&
(reader->node->children == NULL) &&
((reader->node->extra & NODE_IS_EMPTY) == 0) &&
(reader->in_xinclude <= 0)) {
reader->state = XML_TEXTREADER_END;
goto node_found;
}
#ifdef LIBXML_REGEXP_ENABLED
if ((reader->validate) &&
(reader->node->type == XML_ELEMENT_NODE))
xmlTextReaderValidatePop(reader);
#endif /* LIBXML_REGEXP_ENABLED */
if ((reader->preserves > 0) &&
(reader->node->extra & NODE_IS_SPRESERVED))
reader->preserves--;
reader->node = reader->node->next;
reader->state = XML_TEXTREADER_ELEMENT;
/*
* Cleanup of the old node
*/
if ((reader->preserves == 0) &&
(reader->in_xinclude == 0) &&
(reader->entNr == 0) &&
(reader->node->prev != NULL) &&
(reader->node->prev->type != XML_DTD_NODE) &&
(reader->entNr == 0)) {
xmlNodePtr tmp = reader->node->prev;
if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
xmlUnlinkNode(tmp);
xmlTextReaderFreeNode(reader, tmp);
}
}
goto node_found;
}
if ((oldstate == XML_TEXTREADER_ELEMENT) &&
(reader->node->type == XML_ELEMENT_NODE) &&
(reader->node->children == NULL) &&
((reader->node->extra & NODE_IS_EMPTY) == 0)) {;
reader->state = XML_TEXTREADER_END;
goto node_found;
}
#ifdef LIBXML_REGEXP_ENABLED
if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
xmlTextReaderValidatePop(reader);
#endif /* LIBXML_REGEXP_ENABLED */
if ((reader->preserves > 0) &&
(reader->node->extra & NODE_IS_SPRESERVED))
reader->preserves--;
reader->node = reader->node->parent;
if ((reader->node == NULL) ||
(reader->node->type == XML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
(reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
(reader->node->type == XML_HTML_DOCUMENT_NODE)) {
if (reader->mode != XML_TEXTREADER_DONE) {
val = xmlParseChunk(reader->ctxt, "", 0, 1);
reader->mode = XML_TEXTREADER_DONE;
}
reader->node = NULL;
reader->depth = -1;
/*
* Cleanup of the old node
*/
if ((reader->preserves == 0) &&
(reader->in_xinclude == 0) &&
(reader->entNr == 0) &&
(oldnode->type != XML_DTD_NODE) &&
((oldnode->extra & NODE_IS_PRESERVED) == 0) &&
(reader->entNr == 0)) {
xmlUnlinkNode(oldnode);
xmlTextReaderFreeNode(reader, oldnode);
}
goto node_end;
}
if ((reader->preserves == 0) &&
(reader->in_xinclude == 0) &&
(reader->entNr == 0) &&
(reader->node->last != NULL) &&
((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) {
xmlNodePtr tmp = reader->node->last;
xmlUnlinkNode(tmp);
xmlTextReaderFreeNode(reader, tmp);
}
reader->depth--;
reader->state = XML_TEXTREADER_BACKTRACK;
node_found:
DUMP_READER
/*
* If we are in the middle of a piece of CDATA make sure it's finished
*/
if ((reader->node != NULL) &&
(reader->node->next == NULL) &&
((reader->node->type == XML_TEXT_NODE) ||
(reader->node->type == XML_CDATA_SECTION_NODE))) {
xmlTextReaderExpand(reader);
}
#ifdef LIBXML_XINCLUDE_ENABLED
/*
* Handle XInclude if asked for
*/
if ((reader->xinclude) && (reader->node != NULL) &&
(reader->node->type == XML_ELEMENT_NODE) &&
(reader->node->ns != NULL) &&
((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
(xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
if (reader->xincctxt == NULL) {
reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
xmlXIncludeSetFlags(reader->xincctxt, reader->parserFlags);
}
/*
* expand that node and process it
*/
xmlTextReaderExpand(reader);
xmlXIncludeProcessNode(reader->xincctxt, reader->node);
}
if (reader->node->type == XML_XINCLUDE_START) {
reader->in_xinclude++;
goto get_next_node;
}
if (reader->node->type == XML_XINCLUDE_END) {
reader->in_xinclude--;
goto get_next_node;
}
#endif
/*
* Handle entities enter and exit when in entity replacement mode
*/
if ((reader->node != NULL) &&
(reader->node->type == XML_ENTITY_REF_NODE) &&
(reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
/*
* Case where the underlying tree is not availble, lookup the entity
* and walk it.
*/
if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
(reader->ctxt->sax->getEntity != NULL)) {
reader->node->children = (xmlNodePtr)
reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
}
if ((reader->node->children != NULL) &&
(reader->node->children->type == XML_ENTITY_DECL) &&
(reader->node->children->children != NULL)) {
xmlTextReaderEntPush(reader, reader->node);
reader->node = reader->node->children->children;
}
#ifdef LIBXML_REGEXP_ENABLED
} else if ((reader->node != NULL) &&
(reader->node->type == XML_ENTITY_REF_NODE) &&
(reader->ctxt != NULL) && (reader->validate)) {
xmlTextReaderValidateEntity(reader);
#endif /* LIBXML_REGEXP_ENABLED */
}
if ((reader->node != NULL) &&
(reader->node->type == XML_ENTITY_DECL) &&
(reader->ent != NULL) && (reader->ent->children == reader->node)) {
reader->node = xmlTextReaderEntPop(reader);
reader->depth++;
goto get_next_node;
}
#ifdef LIBXML_REGEXP_ENABLED
if ((reader->validate) && (reader->node != NULL)) {
xmlNodePtr node = reader->node;
if ((node->type == XML_ELEMENT_NODE) &&
((reader->state != XML_TEXTREADER_END) &&
(reader->state != XML_TEXTREADER_BACKTRACK))) {
xmlTextReaderValidatePush(reader);
} else if ((node->type == XML_TEXT_NODE) ||
(node->type == XML_CDATA_SECTION_NODE)) {
xmlTextReaderValidateCData(reader, node->content,
xmlStrlen(node->content));
}
}
#endif /* LIBXML_REGEXP_ENABLED */
#ifdef LIBXML_PATTERN_ENABLED
if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) &&
(reader->state != XML_TEXTREADER_BACKTRACK)) {
int i;
for (i = 0;i < reader->patternNr;i++) {
if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) {
xmlTextReaderPreserve(reader);
break;
}
}
}
#endif /* LIBXML_PATTERN_ENABLED */
return(1);
node_end:
reader->mode = XML_TEXTREADER_DONE;
return(0);
}
/**
* xmlTextReaderReadState:
* @reader: the xmlTextReaderPtr used
*
* Gets the read state of the reader.
*
* Returns the state value, or -1 in case of error
*/
int
xmlTextReaderReadState(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
return(reader->mode);
}
/**
* xmlTextReaderExpand:
* @reader: the xmlTextReaderPtr used
*
* Reads the contents of the current node and the full subtree. It then makes
* the subtree available until the next xmlTextReaderRead() call
*
* Returns a node pointer valid until the next xmlTextReaderRead() call
* or NULL in case of error.
*/
xmlNodePtr
xmlTextReaderExpand(xmlTextReaderPtr reader) {
if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
return(NULL);
if (reader->doc != NULL)
return(reader->node);
if (xmlTextReaderDoExpand(reader) < 0)
return(NULL);
return(reader->node);
}
/**
* xmlTextReaderNext:
* @reader: the xmlTextReaderPtr used
*
* Skip to the node following the current one in document order while
* avoiding the subtree if any.
*
* Returns 1 if the node was read successfully, 0 if there is no more
* nodes to read, or -1 in case of error
*/
int
xmlTextReaderNext(xmlTextReaderPtr reader) {
int ret;
xmlNodePtr cur;
if (reader == NULL)
return(-1);
if (reader->doc != NULL)
return(xmlTextReaderNextTree(reader));
cur = reader->node;
if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
return(xmlTextReaderRead(reader));
if (reader->state == XML_TEXTREADER_END)
return(xmlTextReaderRead(reader));
if (cur->extra & NODE_IS_EMPTY)
return(xmlTextReaderRead(reader));
do {
ret = xmlTextReaderRead(reader);
if (ret != 1)
return(ret);
} while (reader->node != cur);
return(xmlTextReaderRead(reader));
}
/**
* xmlTextReaderReadInnerXml:
* @reader: the xmlTextReaderPtr used
*
* Reads the contents of the current node, including child nodes and markup.
*
* Returns a string containing the XML content, or NULL if the current node
* is neither an element nor attribute, or has no child nodes. The
* string must be deallocated by the caller.
*/
xmlChar *
xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
TODO
return(NULL);
}
/**
* xmlTextReaderReadOuterXml:
* @reader: the xmlTextReaderPtr used
*
* Reads the contents of the current node, including child nodes and markup.
*
* Returns a string containing the XML content, or NULL if the current node
* is neither an element nor attribute, or has no child nodes. The
* string must be deallocated by the caller.
*/
xmlChar *
xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
TODO
return(NULL);
}
/**
* xmlTextReaderReadString:
* @reader: the xmlTextReaderPtr used
*
* Reads the contents of an element or a text node as a string.
*
* Returns a string containing the contents of the Element or Text node,
* or NULL if the reader is positioned on any other type of node.
* The string must be deallocated by the caller.
*/
xmlChar *
xmlTextReaderReadString(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
TODO
return(NULL);
}
#if 0
/**
* xmlTextReaderReadBase64:
* @reader: the xmlTextReaderPtr used
* @array: a byte array to store the content.
* @offset: the zero-based index into array where the method should
* begin to write.
* @len: the number of bytes to write.
*
* Reads and decodes the Base64 encoded contents of an element and
* stores the result in a byte buffer.
*
* Returns the number of bytes written to array, or zero if the current
* instance is not positioned on an element or -1 in case of error.
*/
int
xmlTextReaderReadBase64(xmlTextReaderPtr reader,
unsigned char *array ATTRIBUTE_UNUSED,
int offset ATTRIBUTE_UNUSED,
int len ATTRIBUTE_UNUSED) {
if ((reader == NULL) || (reader->ctxt == NULL))
return(-1);
if (reader->ctxt->wellFormed != 1)
return(-1);
if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
return(0);
TODO
return(0);
}
/**
* xmlTextReaderReadBinHex:
* @reader: the xmlTextReaderPtr used
* @array: a byte array to store the content.
* @offset: the zero-based index into array where the method should
* begin to write.
* @len: the number of bytes to write.
*
* Reads and decodes the BinHex encoded contents of an element and
* stores the result in a byte buffer.
*
* Returns the number of bytes written to array, or zero if the current
* instance is not positioned on an element or -1 in case of error.
*/
int
xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
unsigned char *array ATTRIBUTE_UNUSED,
int offset ATTRIBUTE_UNUSED,
int len ATTRIBUTE_UNUSED) {
if ((reader == NULL) || (reader->ctxt == NULL))
return(-1);
if (reader->ctxt->wellFormed != 1)
return(-1);
if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
return(0);
TODO
return(0);
}
#endif
/************************************************************************
* *
* Operating on a preparsed tree *
* *
************************************************************************/
static int
xmlTextReaderNextTree(xmlTextReaderPtr reader)
{
if (reader == NULL)
return(-1);
if (reader->state == XML_TEXTREADER_END)
return(0);
if (reader->node == NULL) {
if (reader->doc->children == NULL) {
reader->state = XML_TEXTREADER_END;
return(0);
}
reader->node = reader->doc->children;
reader->state = XML_TEXTREADER_START;
return(1);
}
if (reader->state != XML_TEXTREADER_BACKTRACK) {
if (reader->node->children != 0) {
reader->node = reader->node->children;
reader->depth++;
reader->state = XML_TEXTREADER_START;
return(1);
}
if ((reader->node->type == XML_ELEMENT_NODE) ||
(reader->node->type == XML_ATTRIBUTE_NODE)) {
reader->state = XML_TEXTREADER_BACKTRACK;
return(1);
}
}
if (reader->node->next != 0) {
reader->node = reader->node->next;
reader->state = XML_TEXTREADER_START;
return(1);
}
if (reader->node->parent != 0) {
if (reader->node->parent->type == XML_DOCUMENT_NODE) {
reader->state = XML_TEXTREADER_END;
return(0);
}
reader->node = reader->node->parent;
reader->depth--;
reader->state = XML_TEXTREADER_BACKTRACK;
return(1);
}
reader->state = XML_TEXTREADER_END;
return(1);
}
/**
* xmlTextReaderReadTree:
* @reader: the xmlTextReaderPtr used
*
* Moves the position of the current instance to the next node in
* the stream, exposing its properties.
*
* Returns 1 if the node was read successfully, 0 if there is no more
* nodes to read, or -1 in case of error
*/
static int
xmlTextReaderReadTree(xmlTextReaderPtr reader) {
if (reader->state == XML_TEXTREADER_END)
return(0);
next_node:
if (reader->node == NULL) {
if (reader->doc->children == NULL) {
reader->state = XML_TEXTREADER_END;
return(0);
}
reader->node = reader->doc->children;
reader->state = XML_TEXTREADER_START;
goto found_node;
}
if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
(reader->node->type != XML_DTD_NODE) &&
(reader->node->type != XML_XINCLUDE_START) &&
(reader->node->type != XML_ENTITY_REF_NODE)) {
if (reader->node->children != NULL) {
reader->node = reader->node->children;
reader->depth++;
reader->state = XML_TEXTREADER_START;
goto found_node;
}
if (reader->node->type == XML_ATTRIBUTE_NODE) {
reader->state = XML_TEXTREADER_BACKTRACK;
goto found_node;
}
}
if (reader->node->next != NULL) {
reader->node = reader->node->next;
reader->state = XML_TEXTREADER_START;
goto found_node;
}
if (reader->node->parent != NULL) {
if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
(reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
reader->state = XML_TEXTREADER_END;
return(0);
}
reader->node = reader->node->parent;
reader->depth--;
reader->state = XML_TEXTREADER_BACKTRACK;
goto found_node;
}
reader->state = XML_TEXTREADER_END;
found_node:
if ((reader->node->type == XML_XINCLUDE_START) ||
(reader->node->type == XML_XINCLUDE_END))
goto next_node;
return(1);
}
/**
* xmlTextReaderNextSibling:
* @reader: the xmlTextReaderPtr used
*
* Skip to the node following the current one in document order while
* avoiding the subtree if any.
* Currently implemented only for Readers built on a document
*
* Returns 1 if the node was read successfully, 0 if there is no more
* nodes to read, or -1 in case of error
*/
int
xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
if (reader->doc == NULL) {
TODO
return(-1);
}
if (reader->state == XML_TEXTREADER_END)
return(0);
if (reader->node == NULL)
return(xmlTextReaderNextTree(reader));
if (reader->node->next != NULL) {
reader->node = reader->node->next;
reader->state = XML_TEXTREADER_START;
return(1);
}
return(0);
}
/************************************************************************
* *
* Constructor and destructors *
* *
************************************************************************/
/**
* xmlNewTextReader:
* @input: the xmlParserInputBufferPtr used to read data
* @URI: the URI information for the source if available
*
* Create an xmlTextReader structure fed with @input
*
* Returns the new xmlTextReaderPtr or NULL in case of error
*/
xmlTextReaderPtr
xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
xmlTextReaderPtr ret;
if (input == NULL)
return(NULL);
ret = xmlMalloc(sizeof(xmlTextReader));
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlNewTextReader : malloc failed\n");
return(NULL);
}
memset(ret, 0, sizeof(xmlTextReader));
ret->doc = NULL;
ret->entTab = NULL;
ret->entMax = 0;
ret->entNr = 0;
ret->input = input;
ret->buffer = xmlBufferCreateSize(100);
ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (ret->sax == NULL) {
xmlFree(ret);
xmlGenericError(xmlGenericErrorContext,
"xmlNewTextReader : malloc failed\n");
return(NULL);
}
xmlSAXVersion(ret->sax, 2);
ret->startElement = ret->sax->startElement;
ret->sax->startElement = xmlTextReaderStartElement;
ret->endElement = ret->sax->endElement;
ret->sax->endElement = xmlTextReaderEndElement;
#ifdef LIBXML_SAX1_ENABLED
if (ret->sax->initialized == XML_SAX2_MAGIC) {
#endif /* LIBXML_SAX1_ENABLED */
ret->startElementNs = ret->sax->startElementNs;
ret->sax->startElementNs = xmlTextReaderStartElementNs;
ret->endElementNs = ret->sax->endElementNs;
ret->sax->endElementNs = xmlTextReaderEndElementNs;
#ifdef LIBXML_SAX1_ENABLED
} else {
ret->startElementNs = NULL;
ret->endElementNs = NULL;
}
#endif /* LIBXML_SAX1_ENABLED */
ret->characters = ret->sax->characters;
ret->sax->characters = xmlTextReaderCharacters;
ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
ret->cdataBlock = ret->sax->cdataBlock;
ret->sax->cdataBlock = xmlTextReaderCDataBlock;
ret->mode = XML_TEXTREADER_MODE_INITIAL;
ret->node = NULL;
ret->curnode = NULL;
if (ret->input->buffer->use < 4) {
xmlParserInputBufferRead(input, 4);
}
if (ret->input->buffer->use >= 4) {
ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
(const char *) ret->input->buffer->content, 4, URI);
ret->base = 0;
ret->cur = 4;
} else {
ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
ret->base = 0;
ret->cur = 0;
}
if (ret->ctxt == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlNewTextReader : malloc failed\n");
xmlFree(ret->sax);
xmlFree(ret);
return(NULL);
}
ret->ctxt->_private = ret;
ret->ctxt->linenumbers = 1;
ret->ctxt->dictNames = 1;
ret->allocs = XML_TEXTREADER_CTXT;
/*
* use the parser dictionnary to allocate all elements and attributes names
*/
ret->ctxt->docdict = 1;
ret->dict = ret->ctxt->dict;
#ifdef LIBXML_XINCLUDE_ENABLED
ret->xinclude = 0;
#endif
#ifdef LIBXML_PATTERN_ENABLED
ret->patternMax = 0;
ret->patternTab = NULL;
#endif
return(ret);
}
/**
* xmlNewTextReaderFilename:
* @URI: the URI of the resource to process
*
* Create an xmlTextReader structure fed with the resource at @URI
*
* Returns the new xmlTextReaderPtr or NULL in case of error
*/
xmlTextReaderPtr
xmlNewTextReaderFilename(const char *URI) {
xmlParserInputBufferPtr input;
xmlTextReaderPtr ret;
char *directory = NULL;
input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
if (input == NULL)
return(NULL);
ret = xmlNewTextReader(input, URI);
if (ret == NULL) {
xmlFreeParserInputBuffer(input);
return(NULL);
}
ret->allocs |= XML_TEXTREADER_INPUT;
if (ret->ctxt->directory == NULL)
directory = xmlParserGetDirectory(URI);
if ((ret->ctxt->directory == NULL) && (directory != NULL))
ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
if (directory != NULL)
xmlFree(directory);
return(ret);
}
/**
* xmlFreeTextReader:
* @reader: the xmlTextReaderPtr
*
* Deallocate all the resources associated to the reader
*/
void
xmlFreeTextReader(xmlTextReaderPtr reader) {
if (reader == NULL)
return;
#ifdef LIBXML_SCHEMAS_ENABLED
if (reader->rngSchemas != NULL) {
xmlRelaxNGFree(reader->rngSchemas);
reader->rngSchemas = NULL;
}
if (reader->rngValidCtxt != NULL) {
xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
reader->rngValidCtxt = NULL;
}
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
if (reader->xincctxt != NULL)
xmlXIncludeFreeContext(reader->xincctxt);
#endif
#ifdef LIBXML_PATTERN_ENABLED
if (reader->patternTab != NULL) {
int i;
for (i = 0;i < reader->patternNr;i++) {
if (reader->patternTab[i] != NULL)
xmlFreePattern(reader->patternTab[i]);
}
xmlFree(reader->patternTab);
}
#endif
if (reader->ctxt != NULL) {
if (reader->dict == reader->ctxt->dict)
reader->dict = NULL;
if (reader->ctxt->myDoc != NULL) {
if (reader->preserve == 0)
xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
reader->ctxt->myDoc = NULL;
}
if ((reader->ctxt->vctxt.vstateTab != NULL) &&
(reader->ctxt->vctxt.vstateMax > 0)){
xmlFree(reader->ctxt->vctxt.vstateTab);
reader->ctxt->vctxt.vstateTab = 0;
reader->ctxt->vctxt.vstateMax = 0;
}
if (reader->allocs & XML_TEXTREADER_CTXT)
xmlFreeParserCtxt(reader->ctxt);
}
if (reader->sax != NULL)
xmlFree(reader->sax);
if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
xmlFreeParserInputBuffer(reader->input);
if (reader->faketext != NULL) {
xmlFreeNode(reader->faketext);
}
if (reader->buffer != NULL)
xmlBufferFree(reader->buffer);
if (reader->entTab != NULL)
xmlFree(reader->entTab);
if (reader->dict != NULL)
xmlDictFree(reader->dict);
xmlFree(reader);
}
/************************************************************************
* *
* Methods for XmlTextReader *
* *
************************************************************************/
/**
* xmlTextReaderClose:
* @reader: the xmlTextReaderPtr used
*
* This method releases any resources allocated by the current instance
* changes the state to Closed and close any underlying input.
*
* Returns 0 or -1 in case of error
*/
int
xmlTextReaderClose(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
reader->node = NULL;
reader->curnode = NULL;
reader->mode = XML_TEXTREADER_MODE_CLOSED;
if (reader->ctxt != NULL) {
if (reader->ctxt->myDoc != NULL) {
if (reader->preserve == 0)
xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
reader->ctxt->myDoc = NULL;
}
if (reader->allocs & XML_TEXTREADER_CTXT) {
xmlFreeParserCtxt(reader->ctxt);
reader->allocs -= XML_TEXTREADER_CTXT;
}
}
if (reader->sax != NULL) {
xmlFree(reader->sax);
reader->sax = NULL;
}
if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
xmlFreeParserInputBuffer(reader->input);
reader->allocs -= XML_TEXTREADER_INPUT;
}
return(0);
}
/**
* xmlTextReaderGetAttributeNo:
* @reader: the xmlTextReaderPtr used
* @no: the zero-based index of the attribute relative to the containing element
*
* Provides the value of the attribute with the specified index relative
* to the containing element.
*
* Returns a string containing the value of the specified attribute, or NULL
* in case of error. The string must be deallocated by the caller.
*/
xmlChar *
xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
xmlChar *ret;
int i;
xmlAttrPtr cur;
xmlNsPtr ns;
if (reader == NULL)
return(NULL);
if (reader->node == NULL)
return(NULL);
if (reader->curnode != NULL)
return(NULL);
/* TODO: handle the xmlDecl */
if (reader->node->type != XML_ELEMENT_NODE)
return(NULL);
ns = reader->node->nsDef;
for (i = 0;(i < no) && (ns != NULL);i++) {
ns = ns->next;
}
if (ns != NULL)
return(xmlStrdup(ns->href));
cur = reader->node->properties;
if (cur == NULL)
return(NULL);
for (;i < no;i++) {
cur = cur->next;
if (cur == NULL)
return(NULL);
}
/* TODO walk the DTD if present */
ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
if (ret == NULL) return(xmlStrdup((xmlChar *)""));
return(ret);
}
/**
* xmlTextReaderGetAttribute:
* @reader: the xmlTextReaderPtr used
* @name: the qualified name of the attribute.
*
* Provides the value of the attribute with the specified qualified name.
*
* Returns a string containing the value of the specified attribute, or NULL
* in case of error. The string must be deallocated by the caller.
*/
xmlChar *
xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
xmlChar *prefix = NULL;
xmlChar *localname;
xmlNsPtr ns;
xmlChar *ret = NULL;
if ((reader == NULL) || (name == NULL))
return(NULL);
if (reader->node == NULL)
return(NULL);
if (reader->curnode != NULL)
return(NULL);
/* TODO: handle the xmlDecl */
if (reader->node->type != XML_ELEMENT_NODE)
return(NULL);
localname = xmlSplitQName2(name, &prefix);
if (localname == NULL)
return(xmlGetProp(reader->node, name));
ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
if (ns != NULL)
ret = xmlGetNsProp(reader->node, localname, ns->href);
if (localname != NULL)
xmlFree(localname);
if (prefix != NULL)
xmlFree(prefix);
return(ret);
}
/**
* xmlTextReaderGetAttributeNs:
* @reader: the xmlTextReaderPtr used
* @localName: the local name of the attribute.
* @namespaceURI: the namespace URI of the attribute.
*
* Provides the value of the specified attribute
*
* Returns a string containing the value of the specified attribute, or NULL
* in case of error. The string must be deallocated by the caller.
*/
xmlChar *
xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
const xmlChar *namespaceURI) {
if ((reader == NULL) || (localName == NULL))
return(NULL);
if (reader->node == NULL)
return(NULL);
if (reader->curnode != NULL)
return(NULL);
/* TODO: handle the xmlDecl */
if (reader->node->type != XML_ELEMENT_NODE)
return(NULL);
return(xmlGetNsProp(reader->node, localName, namespaceURI));
}
/**
* xmlTextReaderGetRemainder:
* @reader: the xmlTextReaderPtr used
*
* Method to get the remainder of the buffered XML. this method stops the
* parser, set its state to End Of File and return the input stream with
* what is left that the parser did not use.
*
* Returns the xmlParserInputBufferPtr attached to the XML or NULL
* in case of error.
*/
xmlParserInputBufferPtr
xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
xmlParserInputBufferPtr ret = NULL;
if (reader == NULL)
return(NULL);
if (reader->node == NULL)
return(NULL);
reader->node = NULL;
reader->curnode = NULL;
reader->mode = XML_TEXTREADER_MODE_EOF;
if (reader->ctxt != NULL) {
if (reader->ctxt->myDoc != NULL) {
if (reader->preserve == 0)
xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
reader->ctxt->myDoc = NULL;
}
if (reader->allocs & XML_TEXTREADER_CTXT) {
xmlFreeParserCtxt(reader->ctxt);
reader->allocs -= XML_TEXTREADER_CTXT;
}
}
if (reader->sax != NULL) {
xmlFree(reader->sax);
reader->sax = NULL;
}
if (reader->allocs & XML_TEXTREADER_INPUT) {
ret = reader->input;
reader->allocs -= XML_TEXTREADER_INPUT;
} else {
/*
* Hum, one may need to duplicate the data structure because
* without reference counting the input may be freed twice:
* - by the layer which allocated it.
* - by the layer to which would have been returned to.
*/
TODO
return(NULL);
}
return(ret);
}
/**
* xmlTextReaderLookupNamespace:
* @reader: the xmlTextReaderPtr used
* @prefix: the prefix whose namespace URI is to be resolved. To return
* the default namespace, specify NULL
*
* Resolves a namespace prefix in the scope of the current element.
*
* Returns a string containing the namespace URI to which the prefix maps
* or NULL in case of error. The string must be deallocated by the caller.
*/
xmlChar *
xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
xmlNsPtr ns;
if (reader == NULL)
return(NULL);
if (reader->node == NULL)
return(NULL);
ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
if (ns == NULL)
return(NULL);
return(xmlStrdup(ns->href));
}
/**
* xmlTextReaderMoveToAttributeNo:
* @reader: the xmlTextReaderPtr used
* @no: the zero-based index of the attribute relative to the containing
* element.
*
* Moves the position of the current instance to the attribute with
* the specified index relative to the containing element.
*
* Returns 1 in case of success, -1 in case of error, 0 if not found
*/
int
xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
int i;
xmlAttrPtr cur;
xmlNsPtr ns;
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(-1);
/* TODO: handle the xmlDecl */
if (reader->node->type != XML_ELEMENT_NODE)
return(-1);
reader->curnode = NULL;
ns = reader->node->nsDef;
for (i = 0;(i < no) && (ns != NULL);i++) {
ns = ns->next;
}
if (ns != NULL) {
reader->curnode = (xmlNodePtr) ns;
return(1);
}
cur = reader->node->properties;
if (cur == NULL)
return(0);
for (;i < no;i++) {
cur = cur->next;
if (cur == NULL)
return(0);
}
/* TODO walk the DTD if present */
reader->curnode = (xmlNodePtr) cur;
return(1);
}
/**
* xmlTextReaderMoveToAttribute:
* @reader: the xmlTextReaderPtr used
* @name: the qualified name of the attribute.
*
* Moves the position of the current instance to the attribute with
* the specified qualified name.
*
* Returns 1 in case of success, -1 in case of error, 0 if not found
*/
int
xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
xmlChar *prefix = NULL;
xmlChar *localname;
xmlNsPtr ns;
xmlAttrPtr prop;
if ((reader == NULL) || (name == NULL))
return(-1);
if (reader->node == NULL)
return(-1);
/* TODO: handle the xmlDecl */
if (reader->node->type != XML_ELEMENT_NODE)
return(0);
localname = xmlSplitQName2(name, &prefix);
if (localname == NULL) {
/*
* Namespace default decl
*/
if (xmlStrEqual(name, BAD_CAST "xmlns")) {
ns = reader->node->nsDef;
while (ns != NULL) {
if (ns->prefix == NULL) {
reader->curnode = (xmlNodePtr) ns;
return(1);
}
ns = ns->next;
}
return(0);
}
prop = reader->node->properties;
while (prop != NULL) {
/*
* One need to have
* - same attribute names
* - and the attribute carrying that namespace
*/
if ((xmlStrEqual(prop->name, name)) &&
((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
reader->curnode = (xmlNodePtr) prop;
return(1);
}
prop = prop->next;
}
return(0);
}
/*
* Namespace default decl
*/
if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
ns = reader->node->nsDef;
while (ns != NULL) {
if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
reader->curnode = (xmlNodePtr) ns;
goto found;
}
ns = ns->next;
}
goto not_found;
}
prop = reader->node->properties;
while (prop != NULL) {
/*
* One need to have
* - same attribute names
* - and the attribute carrying that namespace
*/
if ((xmlStrEqual(prop->name, localname)) &&
(prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
reader->curnode = (xmlNodePtr) prop;
goto found;
}
prop = prop->next;
}
not_found:
if (localname != NULL)
xmlFree(localname);
if (prefix != NULL)
xmlFree(prefix);
return(0);
found:
if (localname != NULL)
xmlFree(localname);
if (prefix != NULL)
xmlFree(prefix);
return(1);
}
/**
* xmlTextReaderMoveToAttributeNs:
* @reader: the xmlTextReaderPtr used
* @localName: the local name of the attribute.
* @namespaceURI: the namespace URI of the attribute.
*
* Moves the position of the current instance to the attribute with the
* specified local name and namespace URI.
*
* Returns 1 in case of success, -1 in case of error, 0 if not found
*/
int
xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
const xmlChar *localName, const xmlChar *namespaceURI) {
xmlAttrPtr prop;
xmlNodePtr node;
if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
return(-1);
if (reader->node == NULL)
return(-1);
if (reader->node->type != XML_ELEMENT_NODE)
return(0);
node = reader->node;
/*
* A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
* namespace name associated to "xmlns"
*/
prop = node->properties;
while (prop != NULL) {
/*
* One need to have
* - same attribute names
* - and the attribute carrying that namespace
*/
if (xmlStrEqual(prop->name, localName) &&
((prop->ns != NULL) &&
(xmlStrEqual(prop->ns->href, namespaceURI)))) {
reader->curnode = (xmlNodePtr) prop;
return(1);
}
prop = prop->next;
}
return(0);
}
/**
* xmlTextReaderMoveToFirstAttribute:
* @reader: the xmlTextReaderPtr used
*
* Moves the position of the current instance to the first attribute
* associated with the current node.
*
* Returns 1 in case of success, -1 in case of error, 0 if not found
*/
int
xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(-1);
if (reader->node->type != XML_ELEMENT_NODE)
return(0);
if (reader->node->nsDef != NULL) {
reader->curnode = (xmlNodePtr) reader->node->nsDef;
return(1);
}
if (reader->node->properties != NULL) {
reader->curnode = (xmlNodePtr) reader->node->properties;
return(1);
}
return(0);
}
/**
* xmlTextReaderMoveToNextAttribute:
* @reader: the xmlTextReaderPtr used
*
* Moves the position of the current instance to the next attribute
* associated with the current node.
*
* Returns 1 in case of success, -1 in case of error, 0 if not found
*/
int
xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(-1);
if (reader->node->type != XML_ELEMENT_NODE)
return(0);
if (reader->curnode == NULL)
return(xmlTextReaderMoveToFirstAttribute(reader));
if (reader->curnode->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) reader->curnode;
if (ns->next != NULL) {
reader->curnode = (xmlNodePtr) ns->next;
return(1);
}
if (reader->node->properties != NULL) {
reader->curnode = (xmlNodePtr) reader->node->properties;
return(1);
}
return(0);
} else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
(reader->curnode->next != NULL)) {
reader->curnode = reader->curnode->next;
return(1);
}
return(0);
}
/**
* xmlTextReaderMoveToElement:
* @reader: the xmlTextReaderPtr used
*
* Moves the position of the current instance to the node that
* contains the current Attribute node.
*
* Returns 1 in case of success, -1 in case of error, 0 if not moved
*/
int
xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(-1);
if (reader->node->type != XML_ELEMENT_NODE)
return(0);
if (reader->curnode != NULL) {
reader->curnode = NULL;
return(1);
}
return(0);
}
/**
* xmlTextReaderReadAttributeValue:
* @reader: the xmlTextReaderPtr used
*
* Parses an attribute value into one or more Text and EntityReference nodes.
*
* Returns 1 in case of success, 0 if the reader was not positionned on an
* ttribute node or all the attribute values have been read, or -1
* in case of error.
*/
int
xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(-1);
if (reader->curnode == NULL)
return(0);
if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
if (reader->curnode->children == NULL)
return(0);
reader->curnode = reader->curnode->children;
} else if (reader->curnode->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) reader->curnode;
if (reader->faketext == NULL) {
reader->faketext = xmlNewDocText(reader->node->doc,
ns->href);
} else {
if (reader->faketext->content != NULL)
xmlFree(reader->faketext->content);
reader->faketext->content = xmlStrdup(ns->href);
}
reader->curnode = reader->faketext;
} else {
if (reader->curnode->next == NULL)
return(0);
reader->curnode = reader->curnode->next;
}
return(1);
}
/************************************************************************
* *
* Acces API to the current node *
* *
************************************************************************/
/**
* xmlTextReaderAttributeCount:
* @reader: the xmlTextReaderPtr used
*
* Provides the number of attributes of the current node
*
* Returns 0 i no attributes, -1 in case of error or the attribute count
*/
int
xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
int ret;
xmlAttrPtr attr;
xmlNsPtr ns;
xmlNodePtr node;
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(0);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if (node->type != XML_ELEMENT_NODE)
return(0);
if ((reader->state == XML_TEXTREADER_END) ||
(reader->state == XML_TEXTREADER_BACKTRACK))
return(0);
ret = 0;
attr = node->properties;
while (attr != NULL) {
ret++;
attr = attr->next;
}
ns = node->nsDef;
while (ns != NULL) {
ret++;
ns = ns->next;
}
return(ret);
}
/**
* xmlTextReaderNodeType:
* @reader: the xmlTextReaderPtr used
*
* Get the node type of the current node
* Reference:
* http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
*
* Returns the xmlNodeType of the current node or -1 in case of error
*/
int
xmlTextReaderNodeType(xmlTextReaderPtr reader) {
xmlNodePtr node;
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(XML_READER_TYPE_NONE);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
switch (node->type) {
case XML_ELEMENT_NODE:
if ((reader->state == XML_TEXTREADER_END) ||
(reader->state == XML_TEXTREADER_BACKTRACK))
return(XML_READER_TYPE_END_ELEMENT);
return(XML_READER_TYPE_ELEMENT);
case XML_NAMESPACE_DECL:
case XML_ATTRIBUTE_NODE:
return(XML_READER_TYPE_ATTRIBUTE);
case XML_TEXT_NODE:
if (xmlIsBlankNode(reader->node)) {
if (xmlNodeGetSpacePreserve(reader->node))
return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
else
return(XML_READER_TYPE_WHITESPACE);
} else {
return(XML_READER_TYPE_TEXT);
}
case XML_CDATA_SECTION_NODE:
return(XML_READER_TYPE_CDATA);
case XML_ENTITY_REF_NODE:
return(XML_READER_TYPE_ENTITY_REFERENCE);
case XML_ENTITY_NODE:
return(XML_READER_TYPE_ENTITY);
case XML_PI_NODE:
return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
case XML_COMMENT_NODE:
return(XML_READER_TYPE_COMMENT);
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE:
#endif
return(XML_READER_TYPE_DOCUMENT);
case XML_DOCUMENT_FRAG_NODE:
return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
case XML_NOTATION_NODE:
return(XML_READER_TYPE_NOTATION);
case XML_DOCUMENT_TYPE_NODE:
case XML_DTD_NODE:
return(XML_READER_TYPE_DOCUMENT_TYPE);
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
return(XML_READER_TYPE_NONE);
}
return(-1);
}
/**
* xmlTextReaderIsEmptyElement:
* @reader: the xmlTextReaderPtr used
*
* Check if the current node is empty
*
* Returns 1 if empty, 0 if not and -1 in case of error
*/
int
xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
if ((reader == NULL) || (reader->node == NULL))
return(-1);
if (reader->node->type != XML_ELEMENT_NODE)
return(0);
if (reader->curnode != NULL)
return(0);
if (reader->node->children != NULL)
return(0);
if (reader->state == XML_TEXTREADER_END)
return(0);
if (reader->doc != NULL)
return(1);
if (reader->in_xinclude > 0)
return(1);
return((reader->node->extra & NODE_IS_EMPTY) != 0);
}
/**
* xmlTextReaderLocalName:
* @reader: the xmlTextReaderPtr used
*
* The local name of the node.
*
* Returns the local name or NULL if not available
*/
xmlChar *
xmlTextReaderLocalName(xmlTextReaderPtr reader) {
xmlNodePtr node;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if (node->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) node;
if (ns->prefix == NULL)
return(xmlStrdup(BAD_CAST "xmlns"));
else
return(xmlStrdup(ns->prefix));
}
if ((node->type != XML_ELEMENT_NODE) &&
(node->type != XML_ATTRIBUTE_NODE))
return(xmlTextReaderName(reader));
return(xmlStrdup(node->name));
}
/**
* xmlTextReaderConstLocalName:
* @reader: the xmlTextReaderPtr used
*
* The local name of the node.
*
* Returns the local name or NULL if not available, the
* string will be deallocated with the reader.
*/
const xmlChar *
xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
xmlNodePtr node;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if (node->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) node;
if (ns->prefix == NULL)
return(CONSTSTR(BAD_CAST "xmlns"));
else
return(ns->prefix);
}
if ((node->type != XML_ELEMENT_NODE) &&
(node->type != XML_ATTRIBUTE_NODE))
return(xmlTextReaderConstName(reader));
return(node->name);
}
/**
* xmlTextReaderName:
* @reader: the xmlTextReaderPtr used
*
* The qualified name of the node, equal to Prefix :LocalName.
*
* Returns the local name or NULL if not available
*/
xmlChar *
xmlTextReaderName(xmlTextReaderPtr reader) {
xmlNodePtr node;
xmlChar *ret;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
switch (node->type) {
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
if ((node->ns == NULL) ||
(node->ns->prefix == NULL))
return(xmlStrdup(node->name));
ret = xmlStrdup(node->ns->prefix);
ret = xmlStrcat(ret, BAD_CAST ":");
ret = xmlStrcat(ret, node->name);
return(ret);
case XML_TEXT_NODE:
return(xmlStrdup(BAD_CAST "#text"));
case XML_CDATA_SECTION_NODE:
return(xmlStrdup(BAD_CAST "#cdata-section"));
case XML_ENTITY_NODE:
case XML_ENTITY_REF_NODE:
return(xmlStrdup(node->name));
case XML_PI_NODE:
return(xmlStrdup(node->name));
case XML_COMMENT_NODE:
return(xmlStrdup(BAD_CAST "#comment"));
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE:
#endif
return(xmlStrdup(BAD_CAST "#document"));
case XML_DOCUMENT_FRAG_NODE:
return(xmlStrdup(BAD_CAST "#document-fragment"));
case XML_NOTATION_NODE:
return(xmlStrdup(node->name));
case XML_DOCUMENT_TYPE_NODE:
case XML_DTD_NODE:
return(xmlStrdup(node->name));
case XML_NAMESPACE_DECL: {
xmlNsPtr ns = (xmlNsPtr) node;
ret = xmlStrdup(BAD_CAST "xmlns");
if (ns->prefix == NULL)
return(ret);
ret = xmlStrcat(ret, BAD_CAST ":");
ret = xmlStrcat(ret, ns->prefix);
return(ret);
}
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
return(NULL);
}
return(NULL);
}
/**
* xmlTextReaderConstName:
* @reader: the xmlTextReaderPtr used
*
* The qualified name of the node, equal to Prefix :LocalName.
*
* Returns the local name or NULL if not available, the string is
* deallocated with the reader.
*/
const xmlChar *
xmlTextReaderConstName(xmlTextReaderPtr reader) {
xmlNodePtr node;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
switch (node->type) {
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
if ((node->ns == NULL) ||
(node->ns->prefix == NULL))
return(node->name);
return(CONSTQSTR(node->ns->prefix, node->name));
case XML_TEXT_NODE:
return(CONSTSTR(BAD_CAST "#text"));
case XML_CDATA_SECTION_NODE:
return(CONSTSTR(BAD_CAST "#cdata-section"));
case XML_ENTITY_NODE:
case XML_ENTITY_REF_NODE:
return(CONSTSTR(node->name));
case XML_PI_NODE:
return(CONSTSTR(node->name));
case XML_COMMENT_NODE:
return(CONSTSTR(BAD_CAST "#comment"));
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE:
#endif
return(CONSTSTR(BAD_CAST "#document"));
case XML_DOCUMENT_FRAG_NODE:
return(CONSTSTR(BAD_CAST "#document-fragment"));
case XML_NOTATION_NODE:
return(CONSTSTR(node->name));
case XML_DOCUMENT_TYPE_NODE:
case XML_DTD_NODE:
return(CONSTSTR(node->name));
case XML_NAMESPACE_DECL: {
xmlNsPtr ns = (xmlNsPtr) node;
if (ns->prefix == NULL)
return(CONSTSTR(BAD_CAST "xmlns"));
return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
}
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
return(NULL);
}
return(NULL);
}
/**
* xmlTextReaderPrefix:
* @reader: the xmlTextReaderPtr used
*
* A shorthand reference to the namespace associated with the node.
*
* Returns the prefix or NULL if not available
*/
xmlChar *
xmlTextReaderPrefix(xmlTextReaderPtr reader) {
xmlNodePtr node;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if (node->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) node;
if (ns->prefix == NULL)
return(NULL);
return(xmlStrdup(BAD_CAST "xmlns"));
}
if ((node->type != XML_ELEMENT_NODE) &&
(node->type != XML_ATTRIBUTE_NODE))
return(NULL);
if ((node->ns != NULL) && (node->ns->prefix != NULL))
return(xmlStrdup(node->ns->prefix));
return(NULL);
}
/**
* xmlTextReaderConstPrefix:
* @reader: the xmlTextReaderPtr used
*
* A shorthand reference to the namespace associated with the node.
*
* Returns the prefix or NULL if not available, the string is deallocated
* with the reader.
*/
const xmlChar *
xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
xmlNodePtr node;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if (node->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) node;
if (ns->prefix == NULL)
return(NULL);
return(CONSTSTR(BAD_CAST "xmlns"));
}
if ((node->type != XML_ELEMENT_NODE) &&
(node->type != XML_ATTRIBUTE_NODE))
return(NULL);
if ((node->ns != NULL) && (node->ns->prefix != NULL))
return(CONSTSTR(node->ns->prefix));
return(NULL);
}
/**
* xmlTextReaderNamespaceUri:
* @reader: the xmlTextReaderPtr used
*
* The URI defining the namespace associated with the node.
*
* Returns the namespace URI or NULL if not available
*/
xmlChar *
xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
xmlNodePtr node;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if (node->type == XML_NAMESPACE_DECL)
return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
if ((node->type != XML_ELEMENT_NODE) &&
(node->type != XML_ATTRIBUTE_NODE))
return(NULL);
if (node->ns != NULL)
return(xmlStrdup(node->ns->href));
return(NULL);
}
/**
* xmlTextReaderConstNamespaceUri:
* @reader: the xmlTextReaderPtr used
*
* The URI defining the namespace associated with the node.
*
* Returns the namespace URI or NULL if not available, the string
* will be deallocated with the reader
*/
const xmlChar *
xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
xmlNodePtr node;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if (node->type == XML_NAMESPACE_DECL)
return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
if ((node->type != XML_ELEMENT_NODE) &&
(node->type != XML_ATTRIBUTE_NODE))
return(NULL);
if (node->ns != NULL)
return(CONSTSTR(node->ns->href));
return(NULL);
}
/**
* xmlTextReaderBaseUri:
* @reader: the xmlTextReaderPtr used
*
* The base URI of the node.
*
* Returns the base URI or NULL if not available
*/
xmlChar *
xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
return(xmlNodeGetBase(NULL, reader->node));
}
/**
* xmlTextReaderConstBaseUri:
* @reader: the xmlTextReaderPtr used
*
* The base URI of the node.
*
* Returns the base URI or NULL if not available, the string
* will be deallocated with the reader
*/
const xmlChar *
xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
xmlChar *tmp;
const xmlChar *ret;
if ((reader == NULL) || (reader->node == NULL))
return(NULL);
tmp = xmlNodeGetBase(NULL, reader->node);
if (tmp == NULL)
return(NULL);
ret = CONSTSTR(tmp);
xmlFree(tmp);
return(ret);
}
/**
* xmlTextReaderDepth:
* @reader: the xmlTextReaderPtr used
*
* The depth of the node in the tree.
*
* Returns the depth or -1 in case of error
*/
int
xmlTextReaderDepth(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(0);
if (reader->curnode != NULL) {
if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
(reader->curnode->type == XML_NAMESPACE_DECL))
return(reader->depth + 1);
return(reader->depth + 2);
}
return(reader->depth);
}
/**
* xmlTextReaderHasAttributes:
* @reader: the xmlTextReaderPtr used
*
* Whether the node has attributes.
*
* Returns 1 if true, 0 if false, and -1 in case or error
*/
int
xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
xmlNodePtr node;
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(0);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
if ((node->type == XML_ELEMENT_NODE) &&
(node->properties != NULL))
return(1);
/* TODO: handle the xmlDecl */
return(0);
}
/**
* xmlTextReaderHasValue:
* @reader: the xmlTextReaderPtr used
*
* Whether the node can have a text value.
*
* Returns 1 if true, 0 if false, and -1 in case or error
*/
int
xmlTextReaderHasValue(xmlTextReaderPtr reader) {
xmlNodePtr node;
if (reader == NULL)
return(-1);
if (reader->node == NULL)
return(0);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
switch (node->type) {
case XML_ATTRIBUTE_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_NAMESPACE_DECL:
return(1);
default:
break;
}
return(0);
}
/**
* xmlTextReaderValue:
* @reader: the xmlTextReaderPtr used
*
* Provides the text value of the node if present
*
* Returns the string or NULL if not available. The result must be deallocated
* with xmlFree()
*/
xmlChar *
xmlTextReaderValue(xmlTextReaderPtr reader) {
xmlNodePtr node;
if (reader == NULL)
return(NULL);
if (reader->node == NULL)
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
switch (node->type) {
case XML_NAMESPACE_DECL:
return(xmlStrdup(((xmlNsPtr) node)->href));
case XML_ATTRIBUTE_NODE:{
xmlAttrPtr attr = (xmlAttrPtr) node;
if (attr->parent != NULL)
return (xmlNodeListGetString
(attr->parent->doc, attr->children, 1));
else
return (xmlNodeListGetString(NULL, attr->children, 1));
break;
}
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
if (node->content != NULL)
return (xmlStrdup(node->content));
default:
break;
}
return(NULL);
}
/**
* xmlTextReaderConstValue:
* @reader: the xmlTextReaderPtr used
*
* Provides the text value of the node if present
*
* Returns the string or NULL if not available. The result will be
* deallocated on the next Read() operation.
*/
const xmlChar *
xmlTextReaderConstValue(xmlTextReaderPtr reader) {
xmlNodePtr node;
if (reader == NULL)
return(NULL);
if (reader->node == NULL)
return(NULL);
if (reader->curnode != NULL)
node = reader->curnode;
else
node = reader->node;
switch (node->type) {
case XML_NAMESPACE_DECL:
return(((xmlNsPtr) node)->href);
case XML_ATTRIBUTE_NODE:{
xmlAttrPtr attr = (xmlAttrPtr) node;
if ((attr->children != NULL) &&
(attr->children->type == XML_TEXT_NODE) &&
(attr->children->next == NULL))
return(attr->children->content);
else {
reader->buffer->use = 0;
xmlNodeBufGetContent(reader->buffer, node);
return(reader->buffer->content);
}
break;
}
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
return(node->content);
default:
break;
}
return(NULL);
}
/**
* xmlTextReaderIsDefault:
* @reader: the xmlTextReaderPtr used
*
* Whether an Attribute node was generated from the default value
* defined in the DTD or schema.
*
* Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
*/
int
xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
return(0);
}
/**
* xmlTextReaderQuoteChar:
* @reader: the xmlTextReaderPtr used
*
* The quotation mark character used to enclose the value of an attribute.
*
* Returns " or ' and -1 in case of error
*/
int
xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
/* TODO maybe lookup the attribute value for " first */
return((int) '"');
}
/**
* xmlTextReaderXmlLang:
* @reader: the xmlTextReaderPtr used
*
* The xml:lang scope within which the node resides.
*
* Returns the xml:lang value or NULL if none exists.
*/
xmlChar *
xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
if (reader == NULL)
return(NULL);
if (reader->node == NULL)
return(NULL);
return(xmlNodeGetLang(reader->node));
}
/**
* xmlTextReaderConstXmlLang:
* @reader: the xmlTextReaderPtr used
*
* The xml:lang scope within which the node resides.
*
* Returns the xml:lang value or NULL if none exists.
*/
const xmlChar *
xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
xmlChar *tmp;
const xmlChar *ret;
if (reader == NULL)
return(NULL);
if (reader->node == NULL)
return(NULL);
tmp = xmlNodeGetLang(reader->node);
if (tmp == NULL)
return(NULL);
ret = CONSTSTR(tmp);
xmlFree(tmp);
return(ret);
}
/**
* xmlTextReaderConstString:
* @reader: the xmlTextReaderPtr used
* @str: the string to intern.
*
* Get an interned string from the reader, allows for example to
* speedup string name comparisons
*
* Returns an interned copy of the string or NULL in case of error. The
* string will be deallocated with the reader.
*/
const xmlChar *
xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
if (reader == NULL)
return(NULL);
return(CONSTSTR(str));
}
/**
* xmlTextReaderNormalization:
* @reader: the xmlTextReaderPtr used
*
* The value indicating whether to normalize white space and attribute values.
* Since attribute value and end of line normalizations are a MUST in the XML
* specification only the value true is accepted. The broken bahaviour of
* accepting out of range character entities like &#0; is of course not
* supported either.
*
* Returns 1 or -1 in case of error.
*/
int
xmlTextReaderNormalization(xmlTextReaderPtr reader) {
if (reader == NULL)
return(-1);
return(1);
}
/************************************************************************
* *
* Extensions to the base APIs *
* *
************************************************************************/
/**
* xmlTextReaderSetParserProp:
* @reader: the xmlTextReaderPtr used
* @prop: the xmlParserProperties to set
* @value: usually 0 or 1 to (de)activate it
*
* Change the parser processing behaviour by changing some of its internal
* properties. Note that some properties can only be changed before any
* read has been done.
*
* Returns 0 if the call was successful, or -1 in case of error
*/
int
xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
xmlParserProperties p = (xmlParserProperties) prop;
xmlParserCtxtPtr ctxt;
if ((reader == NULL) || (reader->ctxt == NULL))
return(-1);
ctxt = reader->ctxt;
switch (p) {
case XML_PARSER_LOADDTD:
if (value != 0) {
if (ctxt->loadsubset == 0) {
if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
return(-1);
ctxt->loadsubset = XML_DETECT_IDS;
}
} else {
ctxt->loadsubset = 0;
}
return(0);
case XML_PARSER_DEFAULTATTRS:
if (value != 0) {
ctxt->loadsubset |= XML_COMPLETE_ATTRS;
} else {
if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
ctxt->loadsubset -= XML_COMPLETE_ATTRS;
}
return(0);
case XML_PARSER_VALIDATE:
if (value != 0) {
ctxt->validate = 1;
reader->validate = XML_TEXTREADER_VALIDATE_DTD;
} else {
ctxt->validate = 0;
}
return(0);
case XML_PARSER_SUBST_ENTITIES:
if (value != 0) {
ctxt->replaceEntities = 1;
} else {
ctxt->replaceEntities = 0;
}
return(0);
}
return(-1);
}
/**
* xmlTextReaderGetParserProp:
* @reader: the xmlTextReaderPtr used
* @prop: the xmlParserProperties to get
*
* Read the parser internal property.
*
* Returns the value, usually 0 or 1, or -1 in case of error.
*/
int
xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
xmlParserProperties p = (xmlParserProperties) prop;
xmlParserCtxtPtr ctxt;
if ((reader == NULL) || (reader->ctxt == NULL))
return(-1);
ctxt = reader->ctxt;
switch (p) {
case XML_PARSER_LOADDTD:
if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
return(1);
return(0);
case XML_PARSER_DEFAULTATTRS:
if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
return(1);
return(0);
case XML_PARSER_VALIDATE:
return(reader->validate);
case XML_PARSER_SUBST_ENTITIES:
return(ctxt->replaceEntities);
}
return(-1);
}
/**
* xmlTextReaderCurrentNode:
* @reader: the xmlTextReaderPtr used
*
* Hacking interface allowing to get the xmlNodePtr correponding to the
* current node being accessed by the xmlTextReader. This is dangerous
* because the underlying node may be destroyed on the next Reads.
*
* Returns the xmlNodePtr or NULL in case of error.
*/
xmlNodePtr
xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
if (reader == NULL)
return(NULL);
if (reader->curnode != NULL)
return(reader->curnode);
return(reader->node);
}
/**
* xmlTextReaderPreserve:
* @reader: the xmlTextReaderPtr used
*
*
* current node being accessed by the xmlTextReader. This is dangerous
* because the underlying node may be destroyed on the next Reads.
*
* Returns the xmlNodePtr or NULL in case of error.
*/
xmlNodePtr
xmlTextReaderPreserve(xmlTextReaderPtr reader) {
xmlNodePtr cur, parent;
if (reader == NULL)
return(NULL);
if (reader->curnode != NULL)
cur = reader->curnode;
else
cur = reader->node;
if (cur == NULL)
return(NULL);
if (cur->type != XML_DOCUMENT_NODE) {
cur->extra |= NODE_IS_PRESERVED;
cur->extra |= NODE_IS_SPRESERVED;
}
reader->preserves++;
parent = cur->parent;;
while (parent != NULL) {
if (parent->type == XML_ELEMENT_NODE)
parent->extra |= NODE_IS_PRESERVED;
parent = parent->parent;
}
return(cur);
}
#ifdef LIBXML_PATTERN_ENABLED
/**
* xmlTextReaderPreservePattern:
* @reader: the xmlTextReaderPtr used
* @pattern: an XPath subset pattern
* @namespaces: the prefix definitions, array of [URI, prefix] or NULL
*
* This tells the XML Reader to preserve all nodes matched by the
* pattern. The caller must also use xmlTextReaderCurrentDoc() to
* keep an handle on the resulting document once parsing has finished
*
* Returns a positive number in case of success and -1 in case of error
*/
int
xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
const xmlChar **namespaces)
{
xmlPatternPtr comp;
if ((reader == NULL) || (pattern == NULL))
return(-1);
comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
if (comp == NULL)
return(-1);
if (reader->patternMax <= 0) {
reader->patternMax = 4;
reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
sizeof(reader->patternTab[0]));
if (reader->patternTab == NULL) {
xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
return (-1);
}
}
if (reader->patternNr >= reader->patternMax) {
xmlPatternPtr *tmp;
reader->patternMax *= 2;
tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
reader->patternMax *
sizeof(reader->patternTab[0]));
if (tmp == NULL) {
xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
reader->patternMax /= 2;
return (-1);
}
reader->patternTab = tmp;
}
reader->patternTab[reader->patternNr] = comp;
return(reader->patternNr++);
}
#endif
/**
* xmlTextReaderCurrentDoc:
* @reader: the xmlTextReaderPtr used
*
* Hacking interface allowing to get the xmlDocPtr correponding to the
* current document being accessed by the xmlTextReader.
* NOTE: as a result of this call, the reader will not destroy the
* associated XML document and calling xmlFreeDoc() on the result
* is needed once the reader parsing has finished.
*
* Returns the xmlDocPtr or NULL in case of error.
*/
xmlDocPtr
xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
if (reader == NULL)
return(NULL);
if (reader->doc != NULL)
return(reader->doc);
if ((reader == NULL) || (reader->ctxt == NULL) ||
(reader->ctxt->myDoc == NULL))
return(NULL);
reader->preserve = 1;
if ((reader->ctxt->myDoc->dict != NULL) &&
(reader->ctxt->myDoc->dict == reader->ctxt->dict))
xmlDictReference(reader->ctxt->dict);
return(reader->ctxt->myDoc);
}
#ifdef LIBXML_SCHEMAS_ENABLED
/**
* xmlTextReaderRelaxNGSetSchema:
* @reader: the xmlTextReaderPtr used
* @schema: a precompiled RelaxNG schema
*
* Use RelaxNG to validate the document as it is processed.
* Activation is only possible before the first Read().
* if @schema is NULL, then RelaxNG validation is desactivated.
@ The @schema should not be freed until the reader is deallocated
* or its use has been deactivated.
*
* Returns 0 in case the RelaxNG validation could be (des)activated and
* -1 in case of error.
*/
int
xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
if (schema == NULL) {
if (reader->rngSchemas != NULL) {
xmlRelaxNGFree(reader->rngSchemas);
reader->rngSchemas = NULL;
}
if (reader->rngValidCtxt != NULL) {
xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
reader->rngValidCtxt = NULL;
}
return(0);
}
if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
return(-1);
if (reader->rngSchemas != NULL) {
xmlRelaxNGFree(reader->rngSchemas);
reader->rngSchemas = NULL;
}
if (reader->rngValidCtxt != NULL) {
xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
reader->rngValidCtxt = NULL;
}
reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
if (reader->rngValidCtxt == NULL)
return(-1);
if (reader->errorFunc != NULL) {
xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
(xmlRelaxNGValidityErrorFunc)reader->errorFunc,
(xmlRelaxNGValidityWarningFunc) reader->errorFunc,
reader->errorFuncArg);
}
reader->rngValidErrors = 0;
reader->rngFullNode = NULL;
reader->validate = XML_TEXTREADER_VALIDATE_RNG;
return(0);
}
/**
* xmlTextReaderRelaxNGValidate:
* @reader: the xmlTextReaderPtr used
* @rng: the path to a RelaxNG schema or NULL
*
* Use RelaxNG to validate the document as it is processed.
* Activation is only possible before the first Read().
* if @rng is NULL, then RelaxNG validation is desactivated.
*
* Returns 0 in case the RelaxNG validation could be (des)activated and
* -1 in case of error.
*/
int
xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
xmlRelaxNGParserCtxtPtr ctxt;
if (reader == NULL)
return(-1);
if (rng == NULL) {
if (reader->rngSchemas != NULL) {
xmlRelaxNGFree(reader->rngSchemas);
reader->rngSchemas = NULL;
}
if (reader->rngValidCtxt != NULL) {
xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
reader->rngValidCtxt = NULL;
}
return(0);
}
if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
return(-1);
if (reader->rngSchemas != NULL) {
xmlRelaxNGFree(reader->rngSchemas);
reader->rngSchemas = NULL;
}
if (reader->rngValidCtxt != NULL) {
xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
reader->rngValidCtxt = NULL;
}
ctxt = xmlRelaxNGNewParserCtxt(rng);
if (reader->errorFunc != NULL) {
xmlRelaxNGSetParserErrors(ctxt,
(xmlRelaxNGValidityErrorFunc) reader->errorFunc,
(xmlRelaxNGValidityWarningFunc) reader->errorFunc,
reader->errorFuncArg);
}
reader->rngSchemas = xmlRelaxNGParse(ctxt);
xmlRelaxNGFreeParserCtxt(ctxt);
if (reader->rngSchemas == NULL)
return(-1);
reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
if (reader->rngValidCtxt == NULL)
return(-1);
if (reader->errorFunc != NULL) {
xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
(xmlRelaxNGValidityErrorFunc)reader->errorFunc,
(xmlRelaxNGValidityWarningFunc) reader->errorFunc,
reader->errorFuncArg);
}
reader->rngValidErrors = 0;
reader->rngFullNode = NULL;
reader->validate = XML_TEXTREADER_VALIDATE_RNG;
return(0);
}
#endif
/************************************************************************
* *
* Error Handling Extensions *
* *
************************************************************************/
/* helper to build a xmlMalloc'ed string from a format and va_list */
static char *
xmlTextReaderBuildMessage(const char *msg, va_list ap) {
int size;
int chars;
char *larger;
char *str;
str = (char *) xmlMallocAtomic(150);
if (str == NULL) {
xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
return NULL;
}
size = 150;
while (1) {
chars = vsnprintf(str, size, msg, ap);
if ((chars > -1) && (chars < size))
break;
if (chars > -1)
size += chars + 1;
else
size += 100;
if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
xmlFree(str);
return NULL;
}
str = larger;
}
return str;
}
/**
* xmlTextReaderLocatorLineNumber:
* @locator: the xmlTextReaderLocatorPtr used
*
* Obtain the line number for the given locator.
*
* Returns the line number or -1 in case of error.
*/
int
xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
/* we know that locator is a xmlParserCtxtPtr */
xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
int ret = -1;
if (ctx->node != NULL) {
ret = xmlGetLineNo(ctx->node);
}
else {
/* inspired from error.c */
xmlParserInputPtr input;
input = ctx->input;
if ((input->filename == NULL) && (ctx->inputNr > 1))
input = ctx->inputTab[ctx->inputNr - 2];
if (input != NULL) {
ret = input->line;
}
else {
ret = -1;
}
}
return ret;
}
/**
* xmlTextReaderLocatorBaseURI:
* @locator: the xmlTextReaderLocatorPtr used
*
* Obtain the base URI for the given locator.
*
* Returns the base URI or NULL in case of error.
*/
xmlChar *
xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
/* we know that locator is a xmlParserCtxtPtr */
xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
xmlChar *ret = NULL;
if (ctx->node != NULL) {
ret = xmlNodeGetBase(NULL,ctx->node);
}
else {
/* inspired from error.c */
xmlParserInputPtr input;
input = ctx->input;
if ((input->filename == NULL) && (ctx->inputNr > 1))
input = ctx->inputTab[ctx->inputNr - 2];
if (input != NULL) {
ret = xmlStrdup(BAD_CAST input->filename);
}
else {
ret = NULL;
}
}
return ret;
}
static void
xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity, char *str) {
xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
if (str != NULL) {
reader->errorFunc(reader->errorFuncArg,
str,
severity,
(xmlTextReaderLocatorPtr)ctx);
xmlFree(str);
}
}
static void
xmlTextReaderError(void *ctxt, const char *msg, ...) {
va_list ap;
va_start(ap,msg);
xmlTextReaderGenericError(ctxt,
XML_PARSER_SEVERITY_ERROR,
xmlTextReaderBuildMessage(msg,ap));
va_end(ap);
}
static void
xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
va_list ap;
va_start(ap,msg);
xmlTextReaderGenericError(ctxt,
XML_PARSER_SEVERITY_WARNING,
xmlTextReaderBuildMessage(msg,ap));
va_end(ap);
}
static void
xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
va_list ap;
int len = xmlStrlen((const xmlChar *) msg);
if ((len > 1) && (msg[len - 2] != ':')) {
/*
* some callbacks only report locator information:
* skip them (mimicking behaviour in error.c)
*/
va_start(ap,msg);
xmlTextReaderGenericError(ctxt,
XML_PARSER_SEVERITY_VALIDITY_ERROR,
xmlTextReaderBuildMessage(msg,ap));
va_end(ap);
}
}
static void
xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
va_list ap;
int len = xmlStrlen((const xmlChar *) msg);
if ((len != 0) && (msg[len - 1] != ':')) {
/*
* some callbacks only report locator information:
* skip them (mimicking behaviour in error.c)
*/
va_start(ap,msg);
xmlTextReaderGenericError(ctxt,
XML_PARSER_SEVERITY_VALIDITY_WARNING,
xmlTextReaderBuildMessage(msg,ap));
va_end(ap);
}
}
/**
* xmlTextReaderSetErrorHandler:
* @reader: the xmlTextReaderPtr used
* @f: the callback function to call on error and warnings
* @arg: a user argument to pass to the callback function
*
* Register a callback function that will be called on error and warnings.
*
* If @f is NULL, the default error and warning handlers are restored.
*/
void
xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
xmlTextReaderErrorFunc f,
void *arg) {
if (f != NULL) {
reader->ctxt->sax->error = xmlTextReaderError;
reader->ctxt->vctxt.error = xmlTextReaderValidityError;
reader->ctxt->sax->warning = xmlTextReaderWarning;
reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
reader->errorFunc = f;
reader->errorFuncArg = arg;
}
else {
/* restore defaults */
reader->ctxt->sax->error = xmlParserError;
reader->ctxt->vctxt.error = xmlParserValidityError;
reader->ctxt->sax->warning = xmlParserWarning;
reader->ctxt->vctxt.warning = xmlParserValidityWarning;
reader->errorFunc = NULL;
reader->errorFuncArg = NULL;
}
}
/**
* xmlTextReaderIsValid:
* @reader: the xmlTextReaderPtr used
*
* Retrieve the validity status from the parser context
*
* Returns the flag value 1 if valid, 0 if no, and -1 in case of error
*/
int
xmlTextReaderIsValid(xmlTextReaderPtr reader) {
if (reader == NULL) return(-1);
#ifdef LIBXML_SCHEMAS_ENABLED
if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
return(reader->rngValidErrors == 0);
#endif
if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
return(reader->ctxt->valid);
return(0);
}
/**
* xmlTextReaderGetErrorHandler:
* @reader: the xmlTextReaderPtr used
* @f: the callback function or NULL is no callback has been registered
* @arg: a user argument
*
* Retrieve the error callback function and user argument.
*/
void
xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
xmlTextReaderErrorFunc *f,
void **arg) {
*f = reader->errorFunc;
*arg = reader->errorFuncArg;
}
/************************************************************************
* *
* New set (2.6.0) of simpler and more flexible APIs *
* *
************************************************************************/
/**
* xmlTextReaderSetup:
* @reader: an XML reader
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
* @reuse: keep the context for reuse
*
* Setup an XML reader with new options
*
* Returns 0 in case of success and -1 in case of error.
*/
static int
xmlTextReaderSetup(xmlTextReaderPtr reader,
xmlParserInputBufferPtr input, const char *URL,
const char *encoding, int options)
{
if (reader == NULL)
return (-1);
reader->doc = NULL;
reader->entNr = 0;
reader->parserFlags = options;
reader->validate = XML_TEXTREADER_NOT_VALIDATE;
if ((input != NULL) && (reader->input != NULL) &&
(reader->allocs & XML_TEXTREADER_INPUT)) {
xmlFreeParserInputBuffer(reader->input);
reader->input = NULL;
reader->allocs -= XML_TEXTREADER_INPUT;
}
if (input != NULL) {
reader->input = input;
reader->allocs |= XML_TEXTREADER_INPUT;
}
if (reader->buffer == NULL)
reader->buffer = xmlBufferCreateSize(100);
if (reader->buffer == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlTextReaderSetup : malloc failed\n");
return (-1);
}
if (reader->sax == NULL)
reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (reader->sax == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlTextReaderSetup : malloc failed\n");
return (-1);
}
xmlSAXVersion(reader->sax, 2);
reader->startElement = reader->sax->startElement;
reader->sax->startElement = xmlTextReaderStartElement;
reader->endElement = reader->sax->endElement;
reader->sax->endElement = xmlTextReaderEndElement;
#ifdef LIBXML_SAX1_ENABLED
if (reader->sax->initialized == XML_SAX2_MAGIC) {
#endif /* LIBXML_SAX1_ENABLED */
reader->startElementNs = reader->sax->startElementNs;
reader->sax->startElementNs = xmlTextReaderStartElementNs;
reader->endElementNs = reader->sax->endElementNs;
reader->sax->endElementNs = xmlTextReaderEndElementNs;
#ifdef LIBXML_SAX1_ENABLED
} else {
reader->startElementNs = NULL;
reader->endElementNs = NULL;
}
#endif /* LIBXML_SAX1_ENABLED */
reader->characters = reader->sax->characters;
reader->sax->characters = xmlTextReaderCharacters;
reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
reader->cdataBlock = reader->sax->cdataBlock;
reader->sax->cdataBlock = xmlTextReaderCDataBlock;
reader->mode = XML_TEXTREADER_MODE_INITIAL;
reader->node = NULL;
reader->curnode = NULL;
if (input != NULL) {
if (reader->input->buffer->use < 4) {
xmlParserInputBufferRead(input, 4);
}
if (reader->ctxt == NULL) {
if (reader->input->buffer->use >= 4) {
reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
(const char *) reader->input->buffer->content, 4, URL);
reader->base = 0;
reader->cur = 4;
} else {
reader->ctxt =
xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
reader->base = 0;
reader->cur = 0;
}
} else {
xmlParserInputPtr inputStream;
xmlParserInputBufferPtr buf;
xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
if (reader->ctxt->myDoc != NULL)
xmlDictReference(reader->ctxt->myDoc->dict);
xmlCtxtReset(reader->ctxt);
buf = xmlAllocParserInputBuffer(enc);
if (buf == NULL) return(-1);
inputStream = xmlNewInputStream(reader->ctxt);
if (inputStream == NULL) {
xmlFreeParserInputBuffer(buf);
return(-1);
}
if (URL == NULL)
inputStream->filename = NULL;
else
inputStream->filename = (char *)
xmlCanonicPath((const xmlChar *) URL);
inputStream->buf = buf;
inputStream->base = inputStream->buf->buffer->content;
inputStream->cur = inputStream->buf->buffer->content;
inputStream->end =
&inputStream->buf->buffer->content[inputStream->buf->buffer->use];
inputPush(reader->ctxt, inputStream);
reader->cur = 0;
}
if (reader->ctxt == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlTextReaderSetup : malloc failed\n");
return (-1);
}
}
if (reader->dict != NULL) {
if (reader->ctxt->dict != NULL) {
if (reader->dict != reader->ctxt->dict) {
xmlDictFree(reader->dict);
reader->dict = reader->ctxt->dict;
}
} else {
reader->ctxt->dict = reader->dict;
}
} else {
if (reader->ctxt->dict == NULL)
reader->ctxt->dict = xmlDictCreate();
reader->dict = reader->ctxt->dict;
}
reader->ctxt->_private = reader;
reader->ctxt->linenumbers = 1;
reader->ctxt->dictNames = 1;
/*
* use the parser dictionnary to allocate all elements and attributes names
*/
reader->ctxt->docdict = 1;
#ifdef LIBXML_XINCLUDE_ENABLED
if (reader->xincctxt != NULL) {
xmlXIncludeFreeContext(reader->xincctxt);
reader->xincctxt = NULL;
}
if (options & XML_PARSE_XINCLUDE) {
reader->xinclude = 1;
reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
options -= XML_PARSE_XINCLUDE;
} else
reader->xinclude = 0;
reader->in_xinclude = 0;
#endif
#ifdef LIBXML_PATTERN_ENABLED
if (reader->patternTab == NULL) {
reader->patternNr = 0;
reader->patternMax = 0;
}
while (reader->patternNr > 0) {
reader->patternNr--;
if (reader->patternTab[reader->patternNr] != NULL) {
xmlFreePattern(reader->patternTab[reader->patternNr]);
reader->patternTab[reader->patternNr] = NULL;
}
}
#endif
if (options & XML_PARSE_DTDVALID)
reader->validate = XML_TEXTREADER_VALIDATE_DTD;
xmlCtxtUseOptions(reader->ctxt, options);
if (encoding != NULL) {
xmlCharEncodingHandlerPtr hdlr;
hdlr = xmlFindCharEncodingHandler(encoding);
if (hdlr != NULL)
xmlSwitchToEncoding(reader->ctxt, hdlr);
}
if ((URL != NULL) && (reader->ctxt->input != NULL) &&
(reader->ctxt->input->filename == NULL))
reader->ctxt->input->filename = (char *)
xmlStrdup((const xmlChar *) URL);
reader->doc = NULL;
return (0);
}
/**
* xmlReaderWalker:
* @doc: a preparsed document
*
* Create an xmltextReader for a preparsed document.
*
* Returns the new reader or NULL in case of error.
*/
xmlTextReaderPtr
xmlReaderWalker(xmlDocPtr doc)
{
xmlTextReaderPtr ret;
if (doc == NULL)
return(NULL);
ret = xmlMalloc(sizeof(xmlTextReader));
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlNewTextReader : malloc failed\n");
return(NULL);
}
memset(ret, 0, sizeof(xmlTextReader));
ret->entNr = 0;
ret->input = NULL;
ret->mode = XML_TEXTREADER_MODE_INITIAL;
ret->node = NULL;
ret->curnode = NULL;
ret->base = 0;
ret->cur = 0;
ret->allocs = XML_TEXTREADER_CTXT;
ret->doc = doc;
ret->state = XML_TEXTREADER_START;
ret->dict = xmlDictCreate();
return(ret);
}
/**
* xmlReaderForDoc:
* @cur: a pointer to a zero terminated string
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Create an xmltextReader for an XML in-memory document.
* The parsing flags @options are a combination of xmlParserOption(s).
*
* Returns the new reader or NULL in case of error.
*/
xmlTextReaderPtr
xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
int options)
{
int len;
if (cur == NULL)
return (NULL);
len = xmlStrlen(cur);
return (xmlReaderForMemory
((const char *) cur, len, URL, encoding, options));
}
/**
* xmlReaderForFile:
* @filename: a file or URL
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* parse an XML file from the filesystem or the network.
* The parsing flags @options are a combination of xmlParserOption(s).
*
* Returns the new reader or NULL in case of error.
*/
xmlTextReaderPtr
xmlReaderForFile(const char *filename, const char *encoding, int options)
{
xmlTextReaderPtr reader;
reader = xmlNewTextReaderFilename(filename);
if (reader == NULL)
return (NULL);
xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
return (reader);
}
/**
* xmlReaderForMemory:
* @buffer: a pointer to a char array
* @size: the size of the array
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Create an xmltextReader for an XML in-memory document.
* The parsing flags @options are a combination of xmlParserOption(s).
*
* Returns the new reader or NULL in case of error.
*/
xmlTextReaderPtr
xmlReaderForMemory(const char *buffer, int size, const char *URL,
const char *encoding, int options)
{
xmlTextReaderPtr reader;
xmlParserInputBufferPtr buf;
buf =
xmlParserInputBufferCreateMem(buffer, size,
XML_CHAR_ENCODING_NONE);
if (buf == NULL) {
return (NULL);
}
reader = xmlNewTextReader(buf, URL);
if (reader == NULL) {
xmlFreeParserInputBuffer(buf);
return (NULL);
}
reader->allocs |= XML_TEXTREADER_INPUT;
xmlTextReaderSetup(reader, NULL, URL, encoding, options);
return (reader);
}
/**
* xmlReaderForFd:
* @fd: an open file descriptor
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Create an xmltextReader for an XML from a file descriptor.
* The parsing flags @options are a combination of xmlParserOption(s).
*
* Returns the new reader or NULL in case of error.
*/
xmlTextReaderPtr
xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
{
xmlTextReaderPtr reader;
xmlParserInputBufferPtr input;
if (fd < 0)
return (NULL);
input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
if (input == NULL)
return (NULL);
reader = xmlNewTextReader(input, URL);
if (reader == NULL) {
xmlFreeParserInputBuffer(input);
return (NULL);
}
reader->allocs |= XML_TEXTREADER_INPUT;
xmlTextReaderSetup(reader, NULL, URL, encoding, options);
return (reader);
}
/**
* xmlReaderForIO:
* @ioread: an I/O read function
* @ioclose: an I/O close function
* @ioctx: an I/O handler
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Create an xmltextReader for an XML document from I/O functions and source.
* The parsing flags @options are a combination of xmlParserOption(s).
*
* Returns the new reader or NULL in case of error.
*/
xmlTextReaderPtr
xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
void *ioctx, const char *URL, const char *encoding,
int options)
{
xmlTextReaderPtr reader;
xmlParserInputBufferPtr input;
if (ioread == NULL)
return (NULL);
input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
XML_CHAR_ENCODING_NONE);
if (input == NULL)
return (NULL);
reader = xmlNewTextReader(input, URL);
if (reader == NULL) {
xmlFreeParserInputBuffer(input);
return (NULL);
}
reader->allocs |= XML_TEXTREADER_INPUT;
xmlTextReaderSetup(reader, NULL, URL, encoding, options);
return (reader);
}
/**
* xmlReaderNewWalker:
* @reader: an XML reader
* @doc: a preparsed document
*
* Setup an xmltextReader to parse a preparsed XML document.
* This reuses the existing @reader xmlTextReader.
*
* Returns 0 in case of success and -1 in case of error
*/
int
xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
{
if (doc == NULL)
return (-1);
if (reader == NULL)
return (-1);
if (reader->ctxt != NULL) {
xmlCtxtReset(reader->ctxt);
}
reader->entNr = 0;
reader->input = NULL;
reader->mode = XML_TEXTREADER_MODE_INITIAL;
reader->node = NULL;
reader->curnode = NULL;
reader->base = 0;
reader->cur = 0;
reader->allocs = XML_TEXTREADER_CTXT;
reader->doc = doc;
reader->state = XML_TEXTREADER_START;
if (reader->dict == NULL) {
if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
reader->dict = reader->ctxt->dict;
else
reader->dict = xmlDictCreate();
}
return(0);
}
/**
* xmlReaderNewDoc:
* @reader: an XML reader
* @cur: a pointer to a zero terminated string
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Setup an xmltextReader to parse an XML in-memory document.
* The parsing flags @options are a combination of xmlParserOption(s).
* This reuses the existing @reader xmlTextReader.
*
* Returns 0 in case of success and -1 in case of error
*/
int
xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
const char *URL, const char *encoding, int options)
{
int len;
if (cur == NULL)
return (-1);
if (reader == NULL)
return (-1);
len = xmlStrlen(cur);
return (xmlReaderNewMemory(reader, (const char *)cur, len,
URL, encoding, options));
}
/**
* xmlReaderNewFile:
* @reader: an XML reader
* @filename: a file or URL
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* parse an XML file from the filesystem or the network.
* The parsing flags @options are a combination of xmlParserOption(s).
* This reuses the existing @reader xmlTextReader.
*
* Returns 0 in case of success and -1 in case of error
*/
int
xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
const char *encoding, int options)
{
xmlParserInputBufferPtr input;
if (filename == NULL)
return (-1);
if (reader == NULL)
return (-1);
input =
xmlParserInputBufferCreateFilename(filename,
XML_CHAR_ENCODING_NONE);
if (input == NULL)
return (-1);
return (xmlTextReaderSetup(reader, input, filename, encoding, options));
}
/**
* xmlReaderNewMemory:
* @reader: an XML reader
* @buffer: a pointer to a char array
* @size: the size of the array
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Setup an xmltextReader to parse an XML in-memory document.
* The parsing flags @options are a combination of xmlParserOption(s).
* This reuses the existing @reader xmlTextReader.
*
* Returns 0 in case of success and -1 in case of error
*/
int
xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
const char *URL, const char *encoding, int options)
{
xmlParserInputBufferPtr input;
if (reader == NULL)
return (-1);
if (buffer == NULL)
return (-1);
input = xmlParserInputBufferCreateMem(buffer, size,
XML_CHAR_ENCODING_NONE);
if (input == NULL) {
return (-1);
}
return (xmlTextReaderSetup(reader, input, URL, encoding, options));
}
/**
* xmlReaderNewFd:
* @reader: an XML reader
* @fd: an open file descriptor
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Setup an xmltextReader to parse an XML from a file descriptor.
* The parsing flags @options are a combination of xmlParserOption(s).
* This reuses the existing @reader xmlTextReader.
*
* Returns 0 in case of success and -1 in case of error
*/
int
xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
const char *URL, const char *encoding, int options)
{
xmlParserInputBufferPtr input;
if (fd < 0)
return (-1);
if (reader == NULL)
return (-1);
input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
if (input == NULL)
return (-1);
return (xmlTextReaderSetup(reader, input, URL, encoding, options));
}
/**
* xmlReaderNewIO:
* @reader: an XML reader
* @ioread: an I/O read function
* @ioclose: an I/O close function
* @ioctx: an I/O handler
* @URL: the base URL to use for the document
* @encoding: the document encoding, or NULL
* @options: a combination of xmlParserOption(s)
*
* Setup an xmltextReader to parse an XML document from I/O functions
* and source.
* The parsing flags @options are a combination of xmlParserOption(s).
* This reuses the existing @reader xmlTextReader.
*
* Returns 0 in case of success and -1 in case of error
*/
int
xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
xmlInputCloseCallback ioclose, void *ioctx,
const char *URL, const char *encoding, int options)
{
xmlParserInputBufferPtr input;
if (ioread == NULL)
return (-1);
if (reader == NULL)
return (-1);
input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
XML_CHAR_ENCODING_NONE);
if (input == NULL)
return (-1);
return (xmlTextReaderSetup(reader, input, URL, encoding, options));
}
/************************************************************************
* *
* Utilities *
* *
************************************************************************/
#ifdef NOT_USED_YET
/**
* xmlBase64Decode:
* @in: the input buffer
* @inlen: the size of the input (in), the size read from it (out)
* @to: the output buffer
* @tolen: the size of the output (in), the size written to (out)
*
* Base64 decoder, reads from @in and save in @to
* TODO: tell jody when this is actually exported
*
* Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
* 2 if there wasn't enough space on the output or -1 in case of error.
*/
static int
xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
unsigned char *to, unsigned long *tolen) {
unsigned long incur; /* current index in in[] */
unsigned long inblk; /* last block index in in[] */
unsigned long outcur; /* current index in out[] */
unsigned long inmax; /* size of in[] */
unsigned long outmax; /* size of out[] */
unsigned char cur; /* the current value read from in[] */
unsigned char intmp[4], outtmp[4]; /* temporary buffers for the convert */
int nbintmp; /* number of byte in intmp[] */
int is_ignore; /* cur should be ignored */
int is_end = 0; /* the end of the base64 was found */
int retval = 1;
int i;
if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
return(-1);
incur = 0;
inblk = 0;
outcur = 0;
inmax = *inlen;
outmax = *tolen;
nbintmp = 0;
while (1) {
if (incur >= inmax)
break;
cur = in[incur++];
is_ignore = 0;
if ((cur >= 'A') && (cur <= 'Z'))
cur = cur - 'A';
else if ((cur >= 'a') && (cur <= 'z'))
cur = cur - 'a' + 26;
else if ((cur >= '0') && (cur <= '9'))
cur = cur - '0' + 52;
else if (cur == '+')
cur = 62;
else if (cur == '/')
cur = 63;
else if (cur == '.')
cur = 0;
else if (cur == '=') /*no op , end of the base64 stream */
is_end = 1;
else {
is_ignore = 1;
if (nbintmp == 0)
inblk = incur;
}
if (!is_ignore) {
int nbouttmp = 3;
int is_break = 0;
if (is_end) {
if (nbintmp == 0)
break;
if ((nbintmp == 1) || (nbintmp == 2))
nbouttmp = 1;
else
nbouttmp = 2;
nbintmp = 3;
is_break = 1;
}
intmp[nbintmp++] = cur;
/*
* if intmp is full, push the 4byte sequence as a 3 byte
* sequence out
*/
if (nbintmp == 4) {
nbintmp = 0;
outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
outtmp[1] =
((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
if (outcur + 3 >= outmax) {
retval = 2;
break;
}
for (i = 0; i < nbouttmp; i++)
to[outcur++] = outtmp[i];
inblk = incur;
}
if (is_break) {
retval = 0;
break;
}
}
}
*tolen = outcur;
*inlen = inblk;
return (retval);
}
/*
* Test routine for the xmlBase64Decode function
*/
#if 0
int main(int argc, char **argv) {
char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
char output[100];
char output2[100];
char output3[100];
unsigned long inlen = strlen(input);
unsigned long outlen = 100;
int ret;
unsigned long cons, tmp, tmp2, prod;
/*
* Direct
*/
ret = xmlBase64Decode(input, &inlen, output, &outlen);
output[outlen] = 0;
printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
/*
* output chunking
*/
cons = 0;
prod = 0;
while (cons < inlen) {
tmp = 5;
tmp2 = inlen - cons;
printf("%ld %ld\n", cons, prod);
ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
cons += tmp2;
prod += tmp;
printf("%ld %ld\n", cons, prod);
}
output2[outlen] = 0;
printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
/*
* input chunking
*/
cons = 0;
prod = 0;
while (cons < inlen) {
tmp = 100 - prod;
tmp2 = inlen - cons;
if (tmp2 > 5)
tmp2 = 5;
printf("%ld %ld\n", cons, prod);
ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
cons += tmp2;
prod += tmp;
printf("%ld %ld\n", cons, prod);
}
output3[outlen] = 0;
printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
return(0);
}
#endif
#endif /* NOT_USED_YET */
#endif /* LIBXML_READER_ENABLED */