added the missing entity to the document internal subset to avoid errors

* test/relaxng/docbook_0.xml: added the missing entity to the
  document internal subset to avoid errors if the DocBook catalogs
  are not there
* xmlschemas.c: first cut at implementing xmlSchemaValidateStream()
  untested yet
Daniel
diff --git a/xmlschemas.c b/xmlschemas.c
index 355600f..0c51609 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -23939,6 +23939,329 @@
     return (xmlSchemaVStart(ctxt));
 }
 
+
+/************************************************************************
+ * 									*
+ * 		Function and data for SAX streaming API			*
+ * 									*
+ ************************************************************************/
+typedef struct _xmlSchemaSplitSAXData xmlSchemaSplitSAXData;
+typedef xmlSchemaSplitSAXData *xmlSchemaSplitSAXDataPtr;
+
+struct _xmlSchemaSplitSAXData {
+    xmlSAXHandlerPtr      user_sax;
+    void                 *user_data;
+    xmlSchemaValidCtxtPtr ctxt;
+    xmlSAXHandlerPtr      schemas_sax;
+};
+
+/* All those functions just bounces to the user provided SAX handlers */
+static void
+internalSubsetSplit(void *ctx, const xmlChar *name,
+	       const xmlChar *ExternalID, const xmlChar *SystemID)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->internalSubset != NULL))
+	ctxt->user_sax->internalSubset(ctxt->user_data, name, ExternalID,
+	                               SystemID);
+}
+
+static int
+isStandaloneSplit(void *ctx)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->isStandalone != NULL))
+	return(ctxt->user_sax->isStandalone(ctxt->user_data));
+    return(0);
+}
+
+static int
+hasInternalSubsetSplit(void *ctx)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->hasInternalSubset != NULL))
+	return(ctxt->user_sax->hasInternalSubset(ctxt->user_data));
+    return(0);
+}
+
+static int
+hasExternalSubsetSplit(void *ctx)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->hasExternalSubset != NULL))
+	return(ctxt->user_sax->hasExternalSubset(ctxt->user_data));
+    return(0);
+}
+
+static void
+externalSubsetSplit(void *ctx, const xmlChar *name,
+	       const xmlChar *ExternalID, const xmlChar *SystemID)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->internalSubset != NULL))
+	ctxt->user_sax->internalSubset(ctxt->user_data, name, ExternalID,
+	                               SystemID);
+}
+
+static xmlParserInputPtr
+resolveEntitySplit(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->resolveEntity != NULL))
+	return(ctxt->user_sax->resolveEntity(ctxt->user_data, publicId,
+	                                     systemId));
+    return(NULL);
+}
+
+static xmlEntityPtr
+getEntitySplit(void *ctx, const xmlChar *name)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->getEntity != NULL))
+	return(ctxt->user_sax->getEntity(ctxt->user_data, name));
+    return(NULL);
+}
+
+static xmlEntityPtr
+getParameterEntitySplit(void *ctx, const xmlChar *name)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->getParameterEntity != NULL))
+	return(ctxt->user_sax->getParameterEntity(ctxt->user_data, name));
+    return(NULL);
+}
+
+
+static void
+entityDeclSplit(void *ctx, const xmlChar *name, int type,
+          const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->entityDecl != NULL))
+	ctxt->user_sax->entityDecl(ctxt->user_data, name, type, publicId,
+	                           systemId, content);
+}
+
+static void
+attributeDeclSplit(void *ctx, const xmlChar * elem,
+                   const xmlChar * name, int type, int def,
+                   const xmlChar * defaultValue, xmlEnumerationPtr tree)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->attributeDecl != NULL)) {
+	ctxt->user_sax->attributeDecl(ctxt->user_data, elem, name, type,
+	                              def, defaultValue, tree);
+    } else {
+	xmlFreeEnumeration(tree);
+    }
+}
+
+static void
+elementDeclSplit(void *ctx, const xmlChar *name, int type,
+	    xmlElementContentPtr content)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->elementDecl != NULL))
+	ctxt->user_sax->elementDecl(ctxt->user_data, name, type, content);
+}
+
+static void
+notationDeclSplit(void *ctx, const xmlChar *name,
+	     const xmlChar *publicId, const xmlChar *systemId)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->notationDecl != NULL))
+	ctxt->user_sax->notationDecl(ctxt->user_data, name, publicId,
+	                             systemId);
+}
+
+static void
+unparsedEntityDeclSplit(void *ctx, const xmlChar *name,
+		   const xmlChar *publicId, const xmlChar *systemId,
+		   const xmlChar *notationName)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->unparsedEntityDecl != NULL))
+	ctxt->user_sax->unparsedEntityDecl(ctxt->user_data, name, publicId,
+	                                   systemId, notationName);
+}
+
+static void
+setDocumentLocatorSplit(void *ctx, xmlSAXLocatorPtr loc)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->setDocumentLocator != NULL))
+	ctxt->user_sax->setDocumentLocator(ctxt->user_data, loc);
+}
+
+static void
+startDocumentSplit(void *ctx)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->startDocument != NULL))
+	ctxt->user_sax->startDocument(ctxt->user_data);
+}
+
+static void
+endDocumentSplit(void *ctx)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->endDocument != NULL))
+	ctxt->user_sax->endDocument(ctxt->user_data);
+}
+
+static void
+processingInstructionSplit(void *ctx, const xmlChar *target,
+                      const xmlChar *data)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->processingInstruction != NULL))
+	ctxt->user_sax->processingInstruction(ctxt->user_data, target, data);
+}
+
+static void
+commentSplit(void *ctx, const xmlChar *value)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->comment != NULL))
+	ctxt->user_sax->comment(ctxt->user_data, value);
+}
+
+/*
+ * Varargs error callbacks to the user application, harder ...
+ */
+
+static void
+warningSplit(void *ctx, const char *msg, ...) {
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->warning != NULL)) {
+	TODO
+    }
+}
+static void
+errorSplit(void *ctx, const char *msg, ...) {
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->error != NULL)) {
+	TODO
+    }
+}
+static void
+fatalErrorSplit(void *ctx, const char *msg, ...) {
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->fatalError != NULL)) {
+	TODO
+    }
+}
+
+/*
+ * Those are function where both the user handler and the schemas handler
+ * need to be called.
+ */
+static void
+charactersSplit(void *ctx, const xmlChar *ch, int len)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if (ctxt == NULL)
+        return;
+    if ((ctxt->user_sax != NULL) && (ctxt->user_sax->characters != NULL))
+	ctxt->user_sax->characters(ctxt->user_data, ch, len);
+    if (ctxt->ctxt != NULL)
+	xmlSchemaSAXHandleText(ctxt->ctxt, ch, len);
+}
+
+static void
+ignorableWhitespaceSplit(void *ctx, const xmlChar *ch, int len)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if (ctxt == NULL)
+        return;
+    if ((ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->ignorableWhitespace != NULL))
+	ctxt->user_sax->ignorableWhitespace(ctxt->user_data, ch, len);
+    if (ctxt->ctxt != NULL)
+	xmlSchemaSAXHandleText(ctxt->ctxt, ch, len);
+}
+
+static void
+cdataBlockSplit(void *ctx, const xmlChar *value, int len)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if (ctxt == NULL)
+        return;
+    if ((ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->ignorableWhitespace != NULL))
+	ctxt->user_sax->ignorableWhitespace(ctxt->user_data, value, len);
+    if (ctxt->ctxt != NULL)
+	xmlSchemaSAXHandleCDataSection(ctxt->ctxt, value, len);
+}
+
+static void
+referenceSplit(void *ctx, const xmlChar *name)
+{
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->reference != NULL))
+	ctxt->user_sax->reference(ctxt->user_data, name);
+    if (ctxt->ctxt != NULL)
+        xmlSchemaSAXHandleReference(ctxt->user_data, name);
+}
+
+static void
+startElementNsSplit(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) {
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if (ctxt == NULL)
+        return;
+    if ((ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->startElementNs != NULL))
+	ctxt->user_sax->startElementNs(ctxt->user_data, localname, prefix,
+	                               URI, nb_namespaces, namespaces,
+				       nb_attributes, nb_defaulted,
+				       attributes);
+    if (ctxt->ctxt != NULL)
+	xmlSchemaSAXHandleStartElementNs(ctxt->ctxt, localname, prefix,
+	                                 URI, nb_namespaces, namespaces,
+					 nb_attributes, nb_defaulted,
+					 attributes);
+}
+
+static void
+endElementNsSplit(void *ctx, const xmlChar * localname, 
+		    const xmlChar * prefix, const xmlChar * URI) {
+    xmlSchemaSplitSAXDataPtr ctxt = (xmlSchemaSplitSAXDataPtr) ctx;
+    if (ctxt == NULL)
+        return;
+    if ((ctxt->user_sax != NULL) &&
+        (ctxt->user_sax->endElementNs != NULL))
+	ctxt->user_sax->endElementNs(ctxt->user_data, localname, prefix, URI);
+    if (ctxt->ctxt != NULL)
+	xmlSchemaSAXHandleEndElementNs(ctxt->ctxt, localname, prefix, URI);
+}
+
 /**
  * xmlSchemaValidateStream:
  * @ctxt:  a schema validation context
@@ -23947,7 +24270,9 @@
  * @sax:  a SAX handler for the resulting events
  * @user_data:  the context to provide to the SAX handler.
  *
- * Validate a document tree in memory.
+ * Validate an input based on a flow of SAX event from the parser
+ * and forward the events to the @sax handler with the provided @user_data
+ * the user provided @sax handler must be a SAX2 one.
  *
  * Returns 0 if the document is schemas valid, a positive error code
  *     number otherwise and -1 in case of internal or API error.
@@ -23957,13 +24282,161 @@
                         xmlParserInputBufferPtr input, xmlCharEncoding enc,
                         xmlSAXHandlerPtr sax, void *user_data)
 {
+    xmlSchemaSplitSAXData split_block;
+    xmlSAXHandler schemas_sax;
+    xmlSAXHandlerPtr old_sax;
+    xmlParserCtxtPtr pctxt;
+    xmlParserInputPtr inputStream;
+    int ret;
+
     if ((ctxt == NULL) || (input == NULL))
         return (-1);
+
+    memset(&schemas_sax, 0, sizeof(xmlSAXHandler));
+    schemas_sax.initialized = XML_SAX2_MAGIC;
+    if (sax == NULL) {
+        /*
+	 * go direct, no need for the split block and functions.
+	 */
+	schemas_sax.startElementNs = xmlSchemaSAXHandleStartElementNs;
+	schemas_sax.endElementNs = xmlSchemaSAXHandleEndElementNs;
+	/*
+	 * Note that we use the same text-function for both, to prevent
+	 * the parser from testing for ignorable whitespace.
+	 */
+	schemas_sax.ignorableWhitespace = xmlSchemaSAXHandleText;
+	schemas_sax.characters = xmlSchemaSAXHandleText;
+
+	schemas_sax.cdataBlock = xmlSchemaSAXHandleCDataSection;
+	schemas_sax.reference = xmlSchemaSAXHandleReference;
+	ctxt->user_data = &split_block;
+    } else {
+       /*
+        * Return -1 without parsing if passed a SAXv1 block
+	*/
+       if (sax->initialized != XML_SAX2_MAGIC)
+           return(-1);
+       if ((sax->startElementNs == NULL) && (sax->endElementNs == NULL) &&
+           ((sax->startElement != NULL) || (sax->endElement != NULL)))
+	   return(-1);
+
+       /*
+        * for each callback unused by Schemas initialize it to the Split
+	* routine only if non NULL in the user block, this can speed up 
+	* things at the SAX level.
+	*/
+        if (sax->internalSubset != NULL)
+            schemas_sax.internalSubset = internalSubsetSplit;
+        if (sax->isStandalone != NULL)
+            schemas_sax.isStandalone = isStandaloneSplit;
+        if (sax->hasInternalSubset != NULL)
+            schemas_sax.hasInternalSubset = hasInternalSubsetSplit;
+        if (sax->hasExternalSubset != NULL)
+            schemas_sax.hasExternalSubset = hasExternalSubsetSplit;
+        if (sax->resolveEntity != NULL)
+            schemas_sax.resolveEntity = resolveEntitySplit;
+        if (sax->getEntity != NULL)
+            schemas_sax.getEntity = getEntitySplit;
+        if (sax->entityDecl != NULL)
+            schemas_sax.entityDecl = entityDeclSplit;
+        if (sax->notationDecl != NULL)
+            schemas_sax.notationDecl = notationDeclSplit;
+        if (sax->attributeDecl != NULL)
+            schemas_sax.attributeDecl = attributeDeclSplit;
+        if (sax->elementDecl != NULL)
+            schemas_sax.elementDecl = elementDeclSplit;
+        if (sax->unparsedEntityDecl != NULL)
+            schemas_sax.unparsedEntityDecl = unparsedEntityDeclSplit;
+        if (sax->setDocumentLocator != NULL)
+            schemas_sax.setDocumentLocator = setDocumentLocatorSplit;
+        if (sax->startDocument != NULL)
+            schemas_sax.startDocument = startDocumentSplit;
+        if (sax->endDocument != NULL)
+            schemas_sax.endDocument = endDocumentSplit;
+        if (sax->processingInstruction != NULL)
+            schemas_sax.processingInstruction = processingInstructionSplit;
+        if (sax->comment != NULL)
+            schemas_sax.comment = commentSplit;
+        if (sax->warning != NULL)
+            schemas_sax.warning = warningSplit;
+        if (sax->error != NULL)
+            schemas_sax.error = errorSplit;
+        if (sax->fatalError != NULL)
+            schemas_sax.fatalError = fatalErrorSplit;
+        if (sax->getParameterEntity != NULL)
+            schemas_sax.getParameterEntity = getParameterEntitySplit;
+        if (sax->externalSubset != NULL)
+            schemas_sax.externalSubset = externalSubsetSplit;
+
+	/*
+	 * the 6 schemas callback have to go to the splitter functions
+	 * Note that we use the same text-function for ignorableWhitespace
+	 * if possible, to prevent the parser from testing for ignorable
+	 * whitespace.
+	 */
+        schemas_sax.characters = charactersSplit;
+	if ((sax->ignorableWhitespace != NULL) &&
+	    (sax->ignorableWhitespace != sax->characters))
+	    schemas_sax.ignorableWhitespace = ignorableWhitespaceSplit;
+	else
+	    schemas_sax.ignorableWhitespace = charactersSplit;
+        schemas_sax.cdataBlock = cdataBlockSplit;
+        schemas_sax.reference = referenceSplit;
+        schemas_sax.startElementNs = startElementNsSplit;
+        schemas_sax.endElementNs = endElementNsSplit;
+	ctxt->user_data = &split_block;
+    }
+
+    split_block.user_sax = sax;
+    split_block.user_data = user_data;
     ctxt->input = input;
     ctxt->enc = enc;
-    ctxt->sax = sax;
-    ctxt->user_data = user_data;
-    TODO return (0);
+    ctxt->sax = &schemas_sax;
+
+    /*
+     * prepare the parser
+     */
+    pctxt = xmlNewParserCtxt();
+    if (pctxt == NULL)
+        return (-1);
+    old_sax = pctxt->sax;
+    pctxt->sax = &schemas_sax;
+#if 0
+    if (options)
+        xmlCtxtUseOptions(pctxt, options);
+#endif
+    pctxt->linenumbers = 1;
+
+    inputStream = xmlNewIOInputStream(pctxt, input, XML_CHAR_ENCODING_NONE);;
+    if (inputStream == NULL) {
+        ret = -1;
+	goto done;
+    }
+    inputPush(pctxt, inputStream);
+    ctxt->parserCtxt = pctxt;
+    ctxt->input = input;
+
+    /*
+     * Launch the validation
+     */
+    ctxt->flags |= XML_SCHEMA_VALID_CTXT_FLAG_STREAM;
+    ret = xmlSchemaVStart(ctxt);
+
+    if ((ret == 0) && (! ctxt->parserCtxt->wellFormed)) {
+	ret = ctxt->parserCtxt->errNo;
+	if (ret == 0)
+	    ret = 1;
+    }    
+    ctxt->parserCtxt = NULL;
+    ctxt->sax = NULL;
+    ctxt->user_data = NULL;
+    ctxt->input = NULL;
+
+done:
+    /* cleanup */
+    pctxt->sax = old_sax;
+    xmlFreeParserCtxt(pctxt);
+    return (ret);
 }
 
 /**