tests: Handle entities in SAX tests
diff --git a/result/ent2.sax b/result/ent2.sax
index 07d2ce4..46da6fd 100644
--- a/result/ent2.sax
+++ b/result/ent2.sax
@@ -10,7 +10,6 @@
 SAX.characters(
   , 3)
 SAX.getEntity(title)
-SAX.error: Entity 'title' not defined
 SAX.reference(title)
 SAX.characters(
   This text is about XML, the, 31)
diff --git a/result/ent2.sax2 b/result/ent2.sax2
index d7c8002..6275de4 100644
--- a/result/ent2.sax2
+++ b/result/ent2.sax2
@@ -10,7 +10,6 @@
 SAX.characters(
   , 3)
 SAX.getEntity(title)
-SAX.error: Entity 'title' not defined
 SAX.reference(title)
 SAX.characters(
   This text is about XML, the, 31)
diff --git a/result/ent7.sax b/result/ent7.sax
index 3228de3..7a298d7 100644
--- a/result/ent7.sax
+++ b/result/ent7.sax
@@ -7,11 +7,16 @@
 SAX.entityDecl(sampleEnt, 1, (null), (null), the hyacinth girl)
 SAX.getEntity(sampleEnt)
 SAX.getParameterEntity(sampleEnt)
-SAX.error: PEReference: %sampleEnt; not found
+SAX.elementDecl(item, 4, ...)
+SAX.elementDecl(para, 3, ...)
+SAX.externalSubset(item, , )
+SAX.startElement(item)
+SAX.startElement(para)
 SAX.characters('they called me , 16)
 SAX.getEntity(sampleEnt)
-SAX.error: Entity 'sampleEnt' not defined
+SAX.characters(the hyacinth girl, 17)
 SAX.reference(sampleEnt)
 SAX.characters(', 1)
+SAX.endElement(para)
+SAX.endElement(item)
 SAX.endDocument()
-xmlSAXUserParseFile returned error 27
diff --git a/result/ent7.sax2 b/result/ent7.sax2
index 3228de3..2a53198 100644
--- a/result/ent7.sax2
+++ b/result/ent7.sax2
@@ -7,11 +7,16 @@
 SAX.entityDecl(sampleEnt, 1, (null), (null), the hyacinth girl)
 SAX.getEntity(sampleEnt)
 SAX.getParameterEntity(sampleEnt)
-SAX.error: PEReference: %sampleEnt; not found
+SAX.elementDecl(item, 4, ...)
+SAX.elementDecl(para, 3, ...)
+SAX.externalSubset(item, , )
+SAX.startElementNs(item, NULL, NULL, 0, 0, 0)
+SAX.startElementNs(para, NULL, NULL, 0, 0, 0)
 SAX.characters('they called me , 16)
 SAX.getEntity(sampleEnt)
-SAX.error: Entity 'sampleEnt' not defined
+SAX.characters(the hyacinth girl, 17)
 SAX.reference(sampleEnt)
 SAX.characters(', 1)
+SAX.endElementNs(para, NULL, NULL)
+SAX.endElementNs(item, NULL, NULL)
 SAX.endDocument()
-xmlSAXUserParseFile returned error 27
diff --git a/result/noent/ent7.sax2 b/result/noent/ent7.sax2
index 3228de3..3d0e634 100644
--- a/result/noent/ent7.sax2
+++ b/result/noent/ent7.sax2
@@ -7,11 +7,15 @@
 SAX.entityDecl(sampleEnt, 1, (null), (null), the hyacinth girl)
 SAX.getEntity(sampleEnt)
 SAX.getParameterEntity(sampleEnt)
-SAX.error: PEReference: %sampleEnt; not found
+SAX.elementDecl(item, 4, ...)
+SAX.elementDecl(para, 3, ...)
+SAX.externalSubset(item, , )
+SAX.startElementNs(item, NULL, NULL, 0, 0, 0)
+SAX.startElementNs(para, NULL, NULL, 0, 0, 0)
 SAX.characters('they called me , 16)
 SAX.getEntity(sampleEnt)
-SAX.error: Entity 'sampleEnt' not defined
-SAX.reference(sampleEnt)
+SAX.characters(the hyacinth girl, 17)
 SAX.characters(', 1)
+SAX.endElementNs(para, NULL, NULL)
+SAX.endElementNs(item, NULL, NULL)
 SAX.endDocument()
-xmlSAXUserParseFile returned error 27
diff --git a/result/noent/xml2.sax2 b/result/noent/xml2.sax2
index 141accd..8932f99 100644
--- a/result/noent/xml2.sax2
+++ b/result/noent/xml2.sax2
@@ -8,11 +8,14 @@
 SAX.entityDecl(zz, 4, (null), (null), <!ENTITY tricky "error-prone" >)
 SAX.getParameterEntity(zz)
 SAX.getParameterEntity(xx)
-SAX.error: PEReference: %xx; not found
+SAX.getParameterEntity(zz)
+SAX.entityDecl(tricky, 1, (null), (null), error-prone)
+SAX.getEntity(tricky)
+SAX.externalSubset(test, , )
+SAX.startElementNs(test, NULL, NULL, 0, 0, 0)
 SAX.characters(This sample shows a , 20)
 SAX.getEntity(tricky)
-SAX.error: Entity 'tricky' not defined
-SAX.reference(tricky)
+SAX.characters(error-prone, 11)
 SAX.characters( method., 8)
+SAX.endElementNs(test, NULL, NULL)
 SAX.endDocument()
-xmlSAXUserParseFile returned error 27
diff --git a/result/xml2.sax b/result/xml2.sax
index 141accd..ced4c73 100644
--- a/result/xml2.sax
+++ b/result/xml2.sax
@@ -8,11 +8,15 @@
 SAX.entityDecl(zz, 4, (null), (null), <!ENTITY tricky "error-prone" >)
 SAX.getParameterEntity(zz)
 SAX.getParameterEntity(xx)
-SAX.error: PEReference: %xx; not found
+SAX.getParameterEntity(zz)
+SAX.entityDecl(tricky, 1, (null), (null), error-prone)
+SAX.getEntity(tricky)
+SAX.externalSubset(test, , )
+SAX.startElement(test)
 SAX.characters(This sample shows a , 20)
 SAX.getEntity(tricky)
-SAX.error: Entity 'tricky' not defined
+SAX.characters(error-prone, 11)
 SAX.reference(tricky)
 SAX.characters( method., 8)
+SAX.endElement(test)
 SAX.endDocument()
-xmlSAXUserParseFile returned error 27
diff --git a/result/xml2.sax2 b/result/xml2.sax2
index 141accd..f66b9e0 100644
--- a/result/xml2.sax2
+++ b/result/xml2.sax2
@@ -8,11 +8,15 @@
 SAX.entityDecl(zz, 4, (null), (null), <!ENTITY tricky "error-prone" >)
 SAX.getParameterEntity(zz)
 SAX.getParameterEntity(xx)
-SAX.error: PEReference: %xx; not found
+SAX.getParameterEntity(zz)
+SAX.entityDecl(tricky, 1, (null), (null), error-prone)
+SAX.getEntity(tricky)
+SAX.externalSubset(test, , )
+SAX.startElementNs(test, NULL, NULL, 0, 0, 0)
 SAX.characters(This sample shows a , 20)
 SAX.getEntity(tricky)
-SAX.error: Entity 'tricky' not defined
+SAX.characters(error-prone, 11)
 SAX.reference(tricky)
 SAX.characters( method., 8)
+SAX.endElementNs(test, NULL, NULL)
 SAX.endDocument()
-xmlSAXUserParseFile returned error 27
diff --git a/runtest.c b/runtest.c
index ed1dfab..37fb2a9 100644
--- a/runtest.c
+++ b/runtest.c
@@ -839,6 +839,12 @@
     NULL  /* xmlStructuredErrorFunc */
 };
 
+typedef struct {
+    const char *filename;
+    xmlHashTablePtr generalEntities;
+    xmlHashTablePtr parameterEntities;
+} debugContext;
+
 static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
 static int callbacks = 0;
 static int quiet = 0;
@@ -997,13 +1003,16 @@
  * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
  */
 static xmlEntityPtr
-getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
+getEntityDebug(void *ctx, const xmlChar *name)
 {
+    debugContext *ctxt = ctx;
+
     callbacks++;
     if (quiet)
 	return(NULL);
     fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
-    return(NULL);
+
+    return(xmlHashLookup(ctxt->generalEntities, name));
 }
 
 /**
@@ -1016,13 +1025,16 @@
  * Returns the xmlParserInputPtr
  */
 static xmlEntityPtr
-getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
+getParameterEntityDebug(void *ctx, const xmlChar *name)
 {
+    debugContext *ctxt = ctx;
+
     callbacks++;
     if (quiet)
 	return(NULL);
     fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
-    return(NULL);
+
+    return(xmlHashLookup(ctxt->parameterEntities, name));
 }
 
 
@@ -1038,10 +1050,13 @@
  * An entity definition has been parsed
  */
 static void
-entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
+entityDeclDebug(void *ctx, const xmlChar *name, int type,
           const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
 {
-const xmlChar *nullstr = BAD_CAST "(null)";
+    debugContext *ctxt = ctx;
+    xmlEntityPtr ent;
+    const xmlChar *nullstr = BAD_CAST "(null)";
+
     /* not all libraries handle printing null pointers nicely */
     if (publicId == NULL)
         publicId = nullstr;
@@ -1054,6 +1069,16 @@
 	return;
     fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
             name, type, publicId, systemId, content);
+
+    ent = xmlNewEntity(NULL, name, type, publicId, systemId, content);
+    if (systemId != NULL)
+        ent->URI = xmlBuildURI(systemId, (const xmlChar *) ctxt->filename);
+
+    if ((type == XML_INTERNAL_PARAMETER_ENTITY) ||
+        (type == XML_EXTERNAL_PARAMETER_ENTITY))
+        xmlHashAddEntry(ctxt->parameterEntities, name, ent);
+    else
+        xmlHashAddEntry(ctxt->generalEntities, name, ent);
 }
 
 /**
@@ -1711,6 +1736,13 @@
 static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
 #endif /* LIBXML_HTML_ENABLED */
 
+static void
+hashFreeEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
+    xmlEntityPtr ent = payload;
+
+    xmlFreeEntity(ent);
+}
+
 /**
  * saxParseTest:
  * @filename: the file to parse
@@ -1784,16 +1816,24 @@
     } else
 #endif
     {
+        debugContext userData;
         xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
+
         if (options & XML_PARSE_SAX1) {
             memcpy(ctxt->sax, debugSAXHandler, sizeof(xmlSAXHandler));
             options -= XML_PARSE_SAX1;
         } else {
             memcpy(ctxt->sax, debugSAX2Handler, sizeof(xmlSAXHandler));
         }
+        userData.filename = filename;
+        userData.generalEntities = xmlHashCreate(0);
+        userData.parameterEntities = xmlHashCreate(0);
+        ctxt->userData = &userData;
         xmlCtxtUseOptions(ctxt, options);
         xmlParseDocument(ctxt);
         ret = ctxt->wellFormed ? 0 : ctxt->errNo;
+        xmlHashFree(userData.generalEntities, hashFreeEntity);
+        xmlHashFree(userData.parameterEntities, hashFreeEntity);
         xmlFreeDoc(ctxt->myDoc);
         xmlFreeParserCtxt(ctxt);
     }