diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 4ec3ca5ba..c29e9f9ee 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 49386 - avoid NPE when extracting OOXML file properties which are dates 49377 - only call DecimalFormat.setRoundingMode on Java 1.6 - it's needed to match excel's rendering of numbers 49378 - correct 1.6ism Parse the HSMF headers chunk if present, and use it to find Dates in text extraction if needed diff --git a/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java b/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java index 47fe05ed9..6d3134055 100644 --- a/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java +++ b/src/ooxml/java/org/apache/poi/POIXMLPropertiesTextExtractor.java @@ -20,6 +20,8 @@ package org.apache.poi; import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart; import org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty; +import java.util.Date; + /** * A {@link POITextExtractor} for returning the textual * content of the OOXML file properties, eg author @@ -41,6 +43,24 @@ public class POIXMLPropertiesTextExtractor extends POIXMLTextExtractor { public POIXMLPropertiesTextExtractor(POIXMLTextExtractor otherExtractor) { super(otherExtractor.getDocument()); } + + private void appendIfPresent(StringBuffer text, String thing, boolean value) { + appendIfPresent(text, thing, Boolean.toString(value)); + } + private void appendIfPresent(StringBuffer text, String thing, int value) { + appendIfPresent(text, thing, Integer.toString(value)); + } + private void appendIfPresent(StringBuffer text, String thing, Date value) { + if(value == null) { return; } + appendIfPresent(text, thing, value.toString()); + } + private void appendIfPresent(StringBuffer text, String thing, String value) { + if(value == null) { return; } + text.append(thing); + text.append(" = "); + text.append(value); + text.append("\n"); + } /** * Returns the core document properties, eg author @@ -50,25 +70,26 @@ public class POIXMLPropertiesTextExtractor extends POIXMLTextExtractor { PackagePropertiesPart props = getDocument().getProperties().getCoreProperties().getUnderlyingProperties(); - text.append("Category = " + props.getCategoryProperty().getValue() + "\n"); - text.append("ContentStatus = " + props.getContentStatusProperty().getValue() + "\n"); - text.append("ContentType = " + props.getContentTypeProperty().getValue() + "\n"); - text.append("Created = " + props.getCreatedProperty().getValue() + "\n"); - text.append("CreatedString = " + props.getCreatedPropertyString() + "\n"); - text.append("Creator = " + props.getCreatorProperty().getValue() + "\n"); - text.append("Description = " + props.getDescriptionProperty().getValue() + "\n"); - text.append("Identifier = " + props.getIdentifierProperty().getValue() + "\n"); - text.append("Keywords = " + props.getKeywordsProperty().getValue() + "\n"); - text.append("Language = " + props.getLanguageProperty().getValue() + "\n"); - text.append("LastModifiedBy = " + props.getLastModifiedByProperty().getValue() + "\n"); - text.append("LastPrinted = " + props.getLastPrintedProperty().getValue() + "\n"); - text.append("LastPrintedString = " + props.getLastPrintedPropertyString() + "\n"); - text.append("Modified = " + props.getModifiedProperty().getValue() + "\n"); - text.append("ModifiedString = " + props.getModifiedPropertyString() + "\n"); - text.append("Revision = " + props.getRevisionProperty().getValue() + "\n"); - text.append("Subject = " + props.getSubjectProperty().getValue() + "\n"); - text.append("Title = " + props.getTitleProperty().getValue() + "\n"); - text.append("Version = " + props.getVersionProperty().getValue() + "\n"); + appendIfPresent(text, "Category", props.getCategoryProperty().getValue()); + appendIfPresent(text, "Category", props.getCategoryProperty().getValue()); + appendIfPresent(text, "ContentStatus", props.getContentStatusProperty().getValue()); + appendIfPresent(text, "ContentType", props.getContentTypeProperty().getValue()); + appendIfPresent(text, "Created", props.getCreatedProperty().getValue()); + appendIfPresent(text, "CreatedString", props.getCreatedPropertyString()); + appendIfPresent(text, "Creator", props.getCreatorProperty().getValue()); + appendIfPresent(text, "Description", props.getDescriptionProperty().getValue()); + appendIfPresent(text, "Identifier", props.getIdentifierProperty().getValue()); + appendIfPresent(text, "Keywords", props.getKeywordsProperty().getValue()); + appendIfPresent(text, "Language", props.getLanguageProperty().getValue()); + appendIfPresent(text, "LastModifiedBy", props.getLastModifiedByProperty().getValue()); + appendIfPresent(text, "LastPrinted", props.getLastPrintedProperty().getValue()); + appendIfPresent(text, "LastPrintedString", props.getLastPrintedPropertyString()); + appendIfPresent(text, "Modified", props.getModifiedProperty().getValue()); + appendIfPresent(text, "ModifiedString", props.getModifiedPropertyString()); + appendIfPresent(text, "Revision", props.getRevisionProperty().getValue()); + appendIfPresent(text, "Subject", props.getSubjectProperty().getValue()); + appendIfPresent(text, "Title", props.getTitleProperty().getValue()); + appendIfPresent(text, "Version", props.getVersionProperty().getValue()); return text.toString(); } @@ -81,21 +102,21 @@ public class POIXMLPropertiesTextExtractor extends POIXMLTextExtractor { org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties props = getDocument().getProperties().getExtendedProperties().getUnderlyingProperties(); - text.append("Application = " + props.getApplication() + "\n"); - text.append("AppVersion = " + props.getAppVersion() + "\n"); - text.append("Characters = " + props.getCharacters() + "\n"); - text.append("CharactersWithSpaces = " + props.getCharactersWithSpaces() + "\n"); - text.append("Company = " + props.getCompany() + "\n"); - text.append("HyperlinkBase = " + props.getHyperlinkBase() + "\n"); - text.append("HyperlinksChanged = " + props.getHyperlinksChanged() + "\n"); - text.append("Lines = " + props.getLines() + "\n"); - text.append("LinksUpToDate = " + props.getLinksUpToDate() + "\n"); - text.append("Manager = " + props.getManager() + "\n"); - text.append("Pages = " + props.getPages() + "\n"); - text.append("Paragraphs = " + props.getParagraphs() + "\n"); - text.append("PresentationFormat = " + props.getPresentationFormat() + "\n"); - text.append("Template = " + props.getTemplate() + "\n"); - text.append("TotalTime = " + props.getTotalTime() + "\n"); + appendIfPresent(text, "Application", props.getApplication()); + appendIfPresent(text, "AppVersion", props.getAppVersion()); + appendIfPresent(text, "Characters", props.getCharacters()); + appendIfPresent(text, "CharactersWithSpaces", props.getCharactersWithSpaces()); + appendIfPresent(text, "Company", props.getCompany()); + appendIfPresent(text, "HyperlinkBase", props.getHyperlinkBase()); + appendIfPresent(text, "HyperlinksChanged", props.getHyperlinksChanged()); + appendIfPresent(text, "Lines", props.getLines()); + appendIfPresent(text, "LinksUpToDate", props.getLinksUpToDate()); + appendIfPresent(text, "Manager", props.getManager()); + appendIfPresent(text, "Pages", props.getPages()); + appendIfPresent(text, "Paragraphs", props.getParagraphs()); + appendIfPresent(text, "PresentationFormat", props.getPresentationFormat()); + appendIfPresent(text, "Template", props.getTemplate()); + appendIfPresent(text, "TotalTime", props.getTotalTime()); return text.toString(); } diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java index 800895df6..af40d361a 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java @@ -583,10 +583,15 @@ public final class PackagePropertiesPart extends PackagePart implements if (d == null) { return ""; } + Date date = d.getValue(); + if (date == null) { + return ""; + } + SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - return df.format(d.getValue()); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + return df.format(date); } @Override diff --git a/src/ooxml/testcases/org/apache/poi/TestXMLPropertiesTextExtractor.java b/src/ooxml/testcases/org/apache/poi/TestXMLPropertiesTextExtractor.java index 303946a11..b19477f04 100644 --- a/src/ooxml/testcases/org/apache/poi/TestXMLPropertiesTextExtractor.java +++ b/src/ooxml/testcases/org/apache/poi/TestXMLPropertiesTextExtractor.java @@ -16,17 +16,17 @@ ==================================================================== */ package org.apache.poi; -import java.io.File; +import junit.framework.TestCase; -import org.apache.poi.xssf.extractor.XSSFExcelExtractor; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.util.PackageHelper; - -import junit.framework.TestCase; +import org.apache.poi.xslf.XSLFSlideShow; +import org.apache.poi.xssf.extractor.XSSFExcelExtractor; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; public final class TestXMLPropertiesTextExtractor extends TestCase { private static final POIDataSamples _ssSamples = POIDataSamples.getSpreadSheetInstance(); + private static final POIDataSamples _slSamples = POIDataSamples.getSlideShowInstance(); public void testGetFromMainExtractor() throws Exception { OPCPackage pkg = PackageHelper.open(_ssSamples.openResourceAsStream("ExcelWithAttachments.xlsm")); @@ -87,4 +87,23 @@ public final class TestXMLPropertiesTextExtractor extends TestCase { public void testCustom() { // TODO! } + + /** + * Bug #49386 - some properties, especially + * dates can be null + */ + public void testWithSomeNulls() throws Exception { + OPCPackage pkg = OPCPackage.open( + _slSamples.openResourceAsStream("49386-null_dates.pptx") + ); + XSLFSlideShow sl = new XSLFSlideShow(pkg); + + POIXMLPropertiesTextExtractor ext = new POIXMLPropertiesTextExtractor(sl); + ext.getText(); + + String text = ext.getText(); + assertFalse(text.contains("Created =")); // With date is null + assertTrue(text.contains("CreatedString = ")); // Via string is blank + assertTrue(text.contains("LastModifiedBy = IT Client Services")); + } } diff --git a/test-data/slideshow/49386-null_dates.pptx b/test-data/slideshow/49386-null_dates.pptx new file mode 100644 index 000000000..77fc378ce Binary files /dev/null and b/test-data/slideshow/49386-null_dates.pptx differ