From 103b45073c7b504236588b3acc146530205af53c Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Thu, 7 Aug 2014 15:25:17 +0000 Subject: [PATCH] Merged revision(s) 1569991, 1615720, 1615731, 1615780-1615781, 1615893, 1589759 from poi/trunk: Apply suggestions from Uwe Schindler for more secure xml defaults for #54764 and #56164, for xml parsers which support them ........ Add another test file for #54764, and a test that uses it ........ Change the default XMLBeans version used for running to be 2.6, leave 2.3 for compiling the schemas (for maximum compatibility) ........ Before parsing an OOXML document, reset the xmlbeans sax parser to avoid the risk of getting one in an error state (due to XMLBEANS-512). Should be a minimal extra overhead pending a proper fix. Allows us to finish enabling the unit tests for #54764 ........ Correct xmlbeans 2.6 url git-svn-id: https://svn.apache.org/repos/asf/poi/branches/REL_3_10_BRANCH@1616509 13f79535-47bb-0310-9956-ffa450edef68 --- .classpath | 2 +- build.xml | 30 +++--- maven/poi-ooxml-schemas.pom | 2 +- .../java/org/apache/poi/POIXMLDocument.java | 6 ++ .../opc/PackageRelationshipCollection.java | 30 +++--- .../opc/internal/ContentTypeManager.java | 7 +- .../PackagePropertiesUnmarshaller.java | 17 ++-- .../java/org/apache/poi/util/SAXHelper.java | 92 ++++++++++++++++++ .../poi/xssf/model/SharedStringsTable.java | 12 ++- .../apache/poi/openxml4j/opc/TestPackage.java | 24 +++-- .../opc/TestPackageCoreProperties.java | 28 +++++- .../poi/openxml4j/opc/TestRelationships.java | 42 +++++++- .../poi/xssf/usermodel/TestXSSFBugs.java | 35 +++++++ .../openxml4j/CorePropertiesHasEntities.ooxml | Bin 0 -> 11016 bytes .../openxml4j/PackageRelsHasEntities.ooxml | Bin 0 -> 11016 bytes test-data/spreadsheet/54764-2.xlsx | Bin 0 -> 8115 bytes test-data/spreadsheet/54764.xlsx | Bin 0 -> 8016 bytes 17 files changed, 270 insertions(+), 57 deletions(-) create mode 100644 src/ooxml/java/org/apache/poi/util/SAXHelper.java create mode 100644 test-data/openxml4j/CorePropertiesHasEntities.ooxml create mode 100644 test-data/openxml4j/PackageRelsHasEntities.ooxml create mode 100644 test-data/spreadsheet/54764-2.xlsx create mode 100644 test-data/spreadsheet/54764.xlsx diff --git a/.classpath b/.classpath index d3cabd61b..f3e6af28f 100644 --- a/.classpath +++ b/.classpath @@ -20,7 +20,7 @@ - + diff --git a/build.xml b/build.xml index a90ba392a..fede4bce6 100644 --- a/build.xml +++ b/build.xml @@ -146,9 +146,12 @@ under the License. - - + + + @@ -218,7 +221,7 @@ under the License. - + @@ -249,7 +252,7 @@ under the License. - + @@ -408,7 +411,8 @@ under the License. - + + @@ -423,13 +427,17 @@ under the License. - - + + + + + + @@ -474,7 +482,7 @@ under the License. + classpath="${ooxml.xmlbeans23.jar}:${ooxml.jsr173.jar}"/> @@ -513,7 +521,7 @@ under the License. description="Compiles the OOXML encryption xsd files into XmlBeans"> + classpath="${ooxml.xmlbeans23.jar}:${ooxml.jsr173.jar}"/> @@ -1255,7 +1263,7 @@ under the License. - + @@ -1284,7 +1292,7 @@ under the License. - + diff --git a/maven/poi-ooxml-schemas.pom b/maven/poi-ooxml-schemas.pom index 361fe64f3..baf531d54 100644 --- a/maven/poi-ooxml-schemas.pom +++ b/maven/poi-ooxml-schemas.pom @@ -62,7 +62,7 @@ org.apache.xmlbeans xmlbeans - 2.3.0 + 2.6.0 diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocument.java b/src/ooxml/java/org/apache/poi/POIXMLDocument.java index fa41a5744..a1e6f95a8 100644 --- a/src/ooxml/java/org/apache/poi/POIXMLDocument.java +++ b/src/ooxml/java/org/apache/poi/POIXMLDocument.java @@ -34,6 +34,7 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.util.IOUtils; +import org.apache.xmlbeans.impl.common.SystemCache; public abstract class POIXMLDocument extends POIXMLDocumentPart{ public static final String DOCUMENT_CREATOR = "Apache POI"; @@ -55,6 +56,11 @@ public abstract class POIXMLDocument extends POIXMLDocumentPart{ protected POIXMLDocument(OPCPackage pkg) { super(pkg); this.pkg = pkg; + + // Workaround for XMLBEANS-512 - ensure that when we parse + // the file, we start with a fresh XML Parser each time, + // and avoid the risk of getting a SaxHandler that's in error + SystemCache.get().setSaxLoader(null); } /** diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java index e157176eb..f98002b1b 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java @@ -22,10 +22,10 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.TreeMap; +import org.apache.poi.util.SAXHelper; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; -import org.dom4j.io.SAXReader; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidOperationException; import org.apache.poi.util.POILogger; @@ -298,21 +298,19 @@ public final class PackageRelationshipCollection implements return relationshipsByID.values().size(); } - /** - * Parse the relationship part and add all relationship in this collection. - * - * @param relPart - * The package part to parse. - * @throws InvalidFormatException - * Throws if the relationship part is invalid. - */ - private void parseRelationshipsPart(PackagePart relPart) - throws InvalidFormatException { - try { - SAXReader reader = new SAXReader(); - logger.log(POILogger.DEBUG, "Parsing relationship: " + relPart.getPartName()); - Document xmlRelationshipsDoc = reader - .read(relPart.getInputStream()); + /** + * Parse the relationship part and add all relationship in this collection. + * + * @param relPart + * The package part to parse. + * @throws InvalidFormatException + * Throws if the relationship part is invalid. + */ + private void parseRelationshipsPart(PackagePart relPart) + throws InvalidFormatException { + try { + logger.log(POILogger.DEBUG, "Parsing relationship: " + relPart.getPartName()); + Document xmlRelationshipsDoc = SAXHelper.readSAXDocument(relPart.getInputStream()); // Browse default types Element root = xmlRelationshipsDoc.getRootElement(); diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java index b8c30df93..2c3b97a7f 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java @@ -23,8 +23,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.Iterator; import java.util.List; -import java.util.TreeMap; import java.util.Map.Entry; +import java.util.TreeMap; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidOperationException; @@ -33,13 +33,13 @@ import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackagingURIHelper; +import org.apache.poi.util.SAXHelper; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Namespace; import org.dom4j.QName; -import org.dom4j.io.SAXReader; /** * Manage package content types ([Content_Types].xml part). @@ -373,8 +373,7 @@ public abstract class ContentTypeManager { private void parseContentTypesFile(InputStream in) throws InvalidFormatException { try { - SAXReader xmlReader = new SAXReader(); - Document xmlContentTypetDoc = xmlReader.read(in); + Document xmlContentTypetDoc = SAXHelper.readSAXDocument(in); // Default content types List defaultTypes = xmlContentTypetDoc.getRootElement().elements( diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java index 36719d347..6f1d62b8a 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/unmarshallers/PackagePropertiesUnmarshaller.java @@ -23,13 +23,6 @@ import java.util.Iterator; import java.util.List; import java.util.zip.ZipEntry; -import org.dom4j.Attribute; -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.Element; -import org.dom4j.Namespace; -import org.dom4j.QName; -import org.dom4j.io.SAXReader; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.PackageNamespaces; import org.apache.poi.openxml4j.opc.PackagePart; @@ -38,6 +31,13 @@ import org.apache.poi.openxml4j.opc.ZipPackage; import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; import org.apache.poi.openxml4j.opc.internal.PartUnmarshaller; import org.apache.poi.openxml4j.opc.internal.ZipHelper; +import org.apache.poi.util.SAXHelper; +import org.dom4j.Attribute; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.Namespace; +import org.dom4j.QName; /** * Package properties unmarshaller. @@ -118,10 +118,9 @@ public final class PackagePropertiesUnmarshaller implements PartUnmarshaller { "Error while trying to get the part input stream."); } - SAXReader xmlReader = new SAXReader(); Document xmlDoc; try { - xmlDoc = xmlReader.read(in); + xmlDoc = SAXHelper.readSAXDocument(in); /* Check OPC compliance */ diff --git a/src/ooxml/java/org/apache/poi/util/SAXHelper.java b/src/ooxml/java/org/apache/poi/util/SAXHelper.java new file mode 100644 index 000000000..b38b2c2be --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/SAXHelper.java @@ -0,0 +1,92 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.lang.reflect.Method; + +import javax.xml.XMLConstants; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.io.SAXReader; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + +/** + * Provides handy methods for working with SAX parsers and readers + */ +public final class SAXHelper { + private static POILogger logger = POILogFactory.getLogger(SAXHelper.class); + + /** + * Creates a new SAX Reader, with sensible defaults + */ + public static SAXReader getSAXReader() { + SAXReader xmlReader = new SAXReader(); + xmlReader.setValidation(false); + xmlReader.setEntityResolver(new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + return new InputSource(new StringReader("")); + } + }); + trySetSAXFeature(xmlReader, XMLConstants.FEATURE_SECURE_PROCESSING, true); + trySetXercesSecurityManager(xmlReader); + return xmlReader; + } + private static void trySetSAXFeature(SAXReader xmlReader, String feature, boolean enabled) { + try { + xmlReader.setFeature(feature, enabled); + } catch (Exception e) { + logger.log(POILogger.INFO, "SAX Feature unsupported", feature, e); + } + } + private static void trySetXercesSecurityManager(SAXReader xmlReader) { + // Try built-in JVM one first, standalone if not + for (String securityManagerClassName : new String[] { + "com.sun.org.apache.xerces.internal.util.SecurityManager", + "org.apache.xerces.util.SecurityManager" + }) { + try { + Object mgr = Class.forName(securityManagerClassName).newInstance(); + Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE); + setLimit.invoke(mgr, 4096); + xmlReader.setProperty("http://apache.org/xml/properties/security-manager", mgr); + // Stop once one can be setup without error + return; + } catch (Exception e) { + logger.log(POILogger.INFO, "SAX Security Manager could not be setup", e); + } + } + } + + /** + * Parses the given stream via the default (sensible) + * SAX Reader + * @param inp Stream to read the XML data from + * @return the SAX processed Document + */ + public static Document readSAXDocument(InputStream inp) throws DocumentException { + return getSAXReader().read(inp); + } +} diff --git a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java index 432b1faab..420eed7c1 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java @@ -20,16 +20,20 @@ package org.apache.poi.xssf.model; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; -import org.apache.poi.POIXMLDocumentPart; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSst; import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument; -import org.apache.poi.openxml4j.opc.PackagePart; -import org.apache.poi.openxml4j.opc.PackageRelationship; /** diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java index b4ac8bd7c..01116abcf 100644 --- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java +++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java @@ -17,10 +17,19 @@ package org.apache.poi.openxml4j.opc; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.reflect.Field; import java.net.URI; -import java.util.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.TreeMap; import java.util.regex.Pattern; import junit.framework.TestCase; @@ -31,15 +40,15 @@ import org.apache.poi.openxml4j.exceptions.InvalidOperationException; import org.apache.poi.openxml4j.opc.internal.ContentTypeManager; import org.apache.poi.openxml4j.opc.internal.FileHelper; import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; -import org.apache.poi.util.TempFile; -import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; +import org.apache.poi.util.SAXHelper; +import org.apache.poi.util.TempFile; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Namespace; import org.dom4j.QName; -import org.dom4j.io.SAXReader; public final class TestPackage extends TestCase { private static final POILogger logger = POILogFactory.getLogger(TestPackage.class); @@ -211,9 +220,8 @@ public final class TestPackage extends TestCase { private void assertMSCompatibility(OPCPackage pkg) throws Exception { PackagePartName relName = PackagingURIHelper.createPartName(PackageRelationship.getContainerPartRelationship()); PackagePart relPart = pkg.getPart(relName); - SAXReader reader = new SAXReader(); - Document xmlRelationshipsDoc = reader - .read(relPart.getInputStream()); + + Document xmlRelationshipsDoc = SAXHelper.readSAXDocument(relPart.getInputStream()); Element root = xmlRelationshipsDoc.getRootElement(); for (Iterator i = root diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackageCoreProperties.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackageCoreProperties.java index d5ca8936d..d3dfee130 100644 --- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackageCoreProperties.java +++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackageCoreProperties.java @@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; @@ -33,8 +34,8 @@ import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; import org.apache.poi.openxml4j.util.Nullable; -import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; public final class TestPackageCoreProperties extends TestCase { private static final POILogger logger = POILogFactory.getLogger(TestPackageCoreProperties.class); @@ -197,4 +198,29 @@ public final class TestPackageCoreProperties extends TestCase { props2.setTitleProperty("Bug 51444 fixed"); } + public void testEntitiesInCoreProps_56164() throws Exception { + InputStream is = OpenXML4JTestDataSamples.openSampleStream("CorePropertiesHasEntities.ooxml"); + OPCPackage p = OPCPackage.open(is); + is.close(); + + // Should have 3 root relationships + boolean foundDocRel = false, foundCorePropRel = false, foundExtPropRel = false; + for (PackageRelationship pr : p.getRelationships()) { + if (pr.getRelationshipType().equals(PackageRelationshipTypes.CORE_DOCUMENT)) + foundDocRel = true; + if (pr.getRelationshipType().equals(PackageRelationshipTypes.CORE_PROPERTIES)) + foundCorePropRel = true; + if (pr.getRelationshipType().equals(PackageRelationshipTypes.EXTENDED_PROPERTIES)) + foundExtPropRel = true; + } + assertTrue("Core/Doc Relationship not found in " + p.getRelationships(), foundDocRel); + assertTrue("Core Props Relationship not found in " + p.getRelationships(), foundCorePropRel); + assertTrue("Ext Props Relationship not found in " + p.getRelationships(), foundExtPropRel); + + // Get the Core Properties + PackagePropertiesPart props = (PackagePropertiesPart)p.getPackageProperties(); + + // Check + assertEquals("Stefan Kopf", props.getCreatorProperty().getValue()); + } } diff --git a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java index f32935670..6a32c38e5 100644 --- a/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java +++ b/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestRelationships.java @@ -17,15 +17,18 @@ package org.apache.poi.openxml4j.opc; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.net.URI; import java.util.regex.Pattern; import junit.framework.TestCase; import org.apache.poi.openxml4j.OpenXML4JTestDataSamples; -import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; +import org.apache.poi.xwpf.usermodel.XWPFRelation; public class TestRelationships extends TestCase { @@ -309,6 +312,7 @@ public class TestRelationships extends TestCase { URI rel1 = parent.relativize(rId1.getTargetURI()); URI rel11 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId1.getTargetURI()); assertEquals("'Another Sheet'!A1", rel1.getFragment()); + assertEquals("'Another Sheet'!A1", rel11.getFragment()); PackageRelationship rId2 = drawingPart.getRelationship("rId2"); URI rel2 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId2.getTargetURI()); @@ -390,6 +394,40 @@ public class TestRelationships extends TestCase { targetUri = rId1.getTargetURI(); assertEquals("mailto:nobody@nowhere.uk%C2%A0", targetUri.toASCIIString()); assertEquals("nobody@nowhere.uk\u00A0", targetUri.getSchemeSpecificPart()); + } + + public void testEntitiesInRels_56164() throws Exception { + InputStream is = OpenXML4JTestDataSamples.openSampleStream("PackageRelsHasEntities.ooxml"); + OPCPackage p = OPCPackage.open(is); + is.close(); + // Should have 3 root relationships + boolean foundDocRel = false, foundCorePropRel = false, foundExtPropRel = false; + for (PackageRelationship pr : p.getRelationships()) { + if (pr.getRelationshipType().equals(PackageRelationshipTypes.CORE_DOCUMENT)) + foundDocRel = true; + if (pr.getRelationshipType().equals(PackageRelationshipTypes.CORE_PROPERTIES)) + foundCorePropRel = true; + if (pr.getRelationshipType().equals(PackageRelationshipTypes.EXTENDED_PROPERTIES)) + foundExtPropRel = true; + } + assertTrue("Core/Doc Relationship not found in " + p.getRelationships(), foundDocRel); + assertTrue("Core Props Relationship not found in " + p.getRelationships(), foundCorePropRel); + assertTrue("Ext Props Relationship not found in " + p.getRelationships(), foundExtPropRel); + + // Should have normal work parts + boolean foundCoreProps = false, foundDocument = false; + for (PackagePart part : p.getParts()) { + if (part.getPartName().toString().equals("/docProps/core.xml")) { + assertEquals(ContentTypes.CORE_PROPERTIES_PART, part.getContentType()); + foundCoreProps = true; + } + if (part.getPartName().toString().equals("/word/document.xml")) { + assertEquals(XWPFRelation.DOCUMENT.getContentType(), part.getContentType()); + foundDocument = true; + } + } + assertTrue("Core not found in " + p.getParts(), foundCoreProps); + assertTrue("Document not found in " + p.getParts(), foundDocument); } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java index faf5825b0..2c727d0dd 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java @@ -32,6 +32,8 @@ import java.util.List; import org.apache.poi.EncryptedDocumentException; import org.apache.poi.POIDataSamples; import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.POIXMLException; +import org.apache.poi.POIXMLProperties; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; @@ -1440,4 +1442,37 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { fail("Should've raised a EncryptedDocumentException error"); } catch (EncryptedDocumentException e) {} } + + @Test + public void bug54764() throws Exception { + OPCPackage pkg = XSSFTestDataSamples.openSamplePackage("54764.xlsx"); + + // Check the core properties - will be found but empty, due + // to the expansion being too much to be considered valid + POIXMLProperties props = new POIXMLProperties(pkg); + assertEquals(null, props.getCoreProperties().getTitle()); + assertEquals(null, props.getCoreProperties().getSubject()); + assertEquals(null, props.getCoreProperties().getDescription()); + + // Now check the spreadsheet itself + try { + new XSSFWorkbook(pkg); + fail("Should fail as too much expansion occurs"); + } catch(POIXMLException e) { + // Expected + } + + // Try with one with the entities in the Content Types + try { + XSSFTestDataSamples.openSamplePackage("54764-2.xlsx"); + fail("Should fail as too much expansion occurs"); + } catch(Exception e) { + // Expected + } + + // Check we can still parse valid files after all that + Workbook wb = XSSFTestDataSamples.openSampleWorkbook("sample.xlsx"); + assertEquals(3, wb.getNumberOfSheets()); + } + } diff --git a/test-data/openxml4j/CorePropertiesHasEntities.ooxml b/test-data/openxml4j/CorePropertiesHasEntities.ooxml new file mode 100644 index 0000000000000000000000000000000000000000..bdd884b0f0869ec4b618c14e9979c901fa54de51 GIT binary patch literal 11016 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

tBqH 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 literal 0 HcmV?d00001 diff --git a/test-data/spreadsheet/54764-2.xlsx b/test-data/spreadsheet/54764-2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0d942ca8d3a07028e2c568628ff1135ced8cc5f6 GIT binary patch literal 8115 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 Si3R`w7xsmR-3bt%kNyW`*+Sv~ literal 0 HcmV?d00001