From b68dfdc7ef9fd4f8c1e546e440af515a2ee7214e Mon Sep 17 00:00:00 2001 From: claudemamo <823038+claudemamo@users.noreply.github.com> Date: Tue, 16 Mar 2021 23:18:38 +0100 Subject: [PATCH] fix: skip attribute entity references instead of choking when XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES is set to false allow SAXParserFactoryImpl to be customised Refs: FasterXML/aalto-xml#65 --- .../com/fasterxml/aalto/in/ReaderScanner.java | 26 ++++++----- .../aalto/sax/SAXParserFactoryImpl.java | 5 +++ .../aalto/sax/TestEntityResolver.java | 45 ++++++++++++++++++- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/fasterxml/aalto/in/ReaderScanner.java b/src/main/java/com/fasterxml/aalto/in/ReaderScanner.java index e19184e..b2e596e 100644 --- a/src/main/java/com/fasterxml/aalto/in/ReaderScanner.java +++ b/src/main/java/com/fasterxml/aalto/in/ReaderScanner.java @@ -896,20 +896,22 @@ private final int collectValue(int attrPtr, char quoteChar, PName attrName) throwUnexpectedChar(c, "'<' not allowed in attribute value"); case XmlCharTypes.CT_AMP: { - int d = handleEntityInText(false); - if (d == 0) { // unexpanded general entity... not good - reportUnexpandedEntityInAttr(attrName, false); - } - // Ok; does it need a surrogate though? (over 16 bits) - if ((d >> 16) != 0) { - d -= 0x10000; - attrBuffer[attrPtr++] = (char) (0xD800 | (d >> 10)); - d = 0xDC00 | (d & 0x3FF); - if (attrPtr >= attrBuffer.length) { - attrBuffer = _attrCollector.valueBufferFull(); + if (_config.willExpandEntities()) { + int d = handleEntityInText(false); + if (d == 0) { // unexpanded general entity... not good + reportUnexpandedEntityInAttr(attrName, false); + } + // Ok; does it need a surrogate though? (over 16 bits) + if ((d >> 16) != 0) { + d -= 0x10000; + attrBuffer[attrPtr++] = (char) (0xD800 | (d >> 10)); + d = 0xDC00 | (d & 0x3FF); + if (attrPtr >= attrBuffer.length) { + attrBuffer = _attrCollector.valueBufferFull(); + } } + c = (char) d; } - c = (char) d; } break; case XmlCharTypes.CT_ATTR_QUOTE: diff --git a/src/main/java/com/fasterxml/aalto/sax/SAXParserFactoryImpl.java b/src/main/java/com/fasterxml/aalto/sax/SAXParserFactoryImpl.java index 3776d5b..5fc3380 100644 --- a/src/main/java/com/fasterxml/aalto/sax/SAXParserFactoryImpl.java +++ b/src/main/java/com/fasterxml/aalto/sax/SAXParserFactoryImpl.java @@ -37,6 +37,11 @@ public class SAXParserFactoryImpl { final InputFactoryImpl mStaxFactory; + public SAXParserFactoryImpl(InputFactoryImpl inputFactory) + { + mStaxFactory = inputFactory; + } + public SAXParserFactoryImpl() { // defaults should be fine... diff --git a/src/test/java/com/fasterxml/aalto/sax/TestEntityResolver.java b/src/test/java/com/fasterxml/aalto/sax/TestEntityResolver.java index ef02a90..a6c6247 100644 --- a/src/test/java/com/fasterxml/aalto/sax/TestEntityResolver.java +++ b/src/test/java/com/fasterxml/aalto/sax/TestEntityResolver.java @@ -1,14 +1,15 @@ package com.fasterxml.aalto.sax; import java.io.*; +import java.util.concurrent.CountDownLatch; import javax.xml.parsers.SAXParser; +import javax.xml.stream.XMLInputFactory; +import com.fasterxml.aalto.stax.InputFactoryImpl; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; -import com.fasterxml.aalto.sax.*; - /** * Simple unit tests to verify that most fundamental parsing functionality * works via Woodstox SAX implementation. @@ -49,6 +50,46 @@ public void testWithDummyExtSubset() } } + public void testSkipAttributeEntityReference() + throws Exception + { + final String XML = + "\n" + +""; + + SAXParserFactoryImpl spf = new SAXParserFactoryImpl(); + SAXParser sp = spf.newSAXParser(); + DefaultHandler h = new DefaultHandler(); + + try { + sp.parse(new InputSource(new StringReader(XML)), h); + fail(); + } catch (SAXException e) { + verifyException(e, "General entity reference (&replace-me;) encountered in entity expanding mode: operation not (yet) implemented\n at [row,col {unknown-source}]: [2,22]"); + } + + InputFactoryImpl inputFactory = new InputFactoryImpl(); + inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false); + SAXParserFactoryImpl spfKeepEntityReferences = new SAXParserFactoryImpl(inputFactory); + spfKeepEntityReferences.setNamespaceAware(true); + SAXParser spKeepEntityReferences = spfKeepEntityReferences.newSAXParser(); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + spKeepEntityReferences.parse(new InputSource(new StringReader(XML)), new DefaultHandler() { + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) { + assertEquals("root", localName); + assertEquals("root", qName); + assertEquals(1, attributes.getLength()); + assertEquals("&replace-me;", attributes.getValue(0)); + + countDownLatch.countDown(); + } + }); + + assertEquals(0, countDownLatch.getCount()); + } + static class MyResolver implements EntityResolver {