From: Andreas Beeker Date: Fri, 14 Aug 2020 19:08:42 +0000 (+0000) Subject: #64411 - Provide JigSaw modules X-Git-Tag: before_ooxml_3rd_edition~152 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=5caf8e109b8fac9341091b7a7bc94a29db01c267;p=poi.git #64411 - Provide JigSaw modules - use service locator for SlideShowFactory git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1880860 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java b/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java index 84d98e70ac..1424a70608 100644 --- a/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java +++ b/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java @@ -16,46 +16,59 @@ ==================================================================== */ package org.apache.poi.sl.usermodel; +import static org.apache.poi.poifs.crypt.EncryptionInfo.ENCRYPTION_INFO_ENTRY; + +import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; +import org.apache.poi.EmptyFileException; import org.apache.poi.EncryptedDocumentException; -import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; import org.apache.poi.poifs.crypt.Decryptor; import org.apache.poi.poifs.filesystem.DirectoryNode; -import org.apache.poi.poifs.filesystem.DocumentFactoryHelper; import org.apache.poi.poifs.filesystem.FileMagic; -import org.apache.poi.poifs.filesystem.OfficeXmlFileException; import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.util.IOUtils; -@SuppressWarnings("unchecked") -public abstract class SlideShowFactory { +public final class SlideShowFactory { - protected interface CreateSlideShow1 { - SlideShow apply(T t) throws IOException; + private static class Singleton { + private static final SlideShowFactory INSTANCE = new SlideShowFactory(); } - protected interface CreateSlideShow2 { - SlideShow apply(T t, U u) throws IOException; + private interface ProviderMethod { + SlideShow create(SlideShowProvider prov) throws IOException; } - // XMLSlideShow createSlideShow(InputStream stream) - protected static CreateSlideShow1 createXslfByStream; - - // XMLSlideShow createSlideShow(File file, boolean readOnly) - protected static CreateSlideShow2 createXslfByFile; + private final List> provider = new ArrayList<>(); - // HSLFSlideShow createSlideShow(final POIFSFileSystem fs) - protected static CreateSlideShow1 createHslfByPoifs; + private SlideShowFactory() { + ServiceLoader.load(SlideShowProvider.class).forEach(provider::add); + } - // HSLFSlideShow createSlideShow(final DirectoryNode root) - protected static CreateSlideShow1 createHslfByNode; + /** + * Create a new empty SlideShow, either XSLF or HSLF depending + * on the parameter + * + * @param XSLF If an XSLFSlideShow or a HSLFSlideShow should be created + * + * @return The created SlideShow + * + * @throws IOException if an error occurs while creating the objects + */ + public static SlideShow create(boolean XSLF) throws IOException { + return wp(XSLF ? FileMagic.OOXML : FileMagic.OLE2, SlideShowProvider::create); + } /** - * Creates a SlideShow from the given POIFSFileSystem. + * Creates a HSLFSlideShow from the given POIFSFileSystem

+ * + * Note that in order to properly release resources the + * SlideShow should be closed after use. * * @param fs The {@link POIFSFileSystem} to read the document from * @@ -63,31 +76,26 @@ public abstract class SlideShowFactory { * * @throws IOException if an error occurs while reading the data */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(POIFSFileSystem fs) throws IOException { + public static SlideShow create(POIFSFileSystem fs) throws IOException { return create(fs, null); } /** * Creates a SlideShow from the given POIFSFileSystem, which may - * be password protected + * be password protected * - * @param fs The {@link POIFSFileSystem} to read the document from - * @param password The password that should be used or null if no password is necessary. + * @param fs The {@link POIFSFileSystem} to read the document from + * @param password The password that should be used or null if no password is necessary. * - * @return The created SlideShow + * @return The created SlideShow * - * @throws IOException if an error occurs while reading the data + * @throws IOException if an error occurs while reading the data */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(final POIFSFileSystem fs, String password) throws IOException { + private static SlideShow create(final POIFSFileSystem fs, String password) throws IOException { return create(fs.getRoot(), password); } + /** * Creates a SlideShow from the given DirectoryNode. * @@ -97,10 +105,7 @@ public abstract class SlideShowFactory { * * @throws IOException if an error occurs while reading the data */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(final DirectoryNode root) throws IOException { + public static SlideShow create(final DirectoryNode root) throws IOException { return create(root, null); } @@ -116,48 +121,22 @@ public abstract class SlideShowFactory { * * @throws IOException if an error occurs while reading the data */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(final DirectoryNode root, String password) throws IOException { + public static SlideShow create(final DirectoryNode root, String password) throws IOException { // Encrypted OOXML files go inside OLE2 containers, is this one? if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) { - InputStream stream = null; - try { - stream = DocumentFactoryHelper.getDecryptedStream(root, password); - initXslf(); - return (SlideShow) createXslfByStream.apply(stream); - } finally { - IOUtils.closeQuietly(stream); - - // as we processed the full stream already, we can close the filesystem here - // otherwise file handles are leaked - root.getFileSystem().close(); - } - } - - // If we get here, it isn't an encrypted PPTX file - // So, treat it as a regular HSLF PPT one - boolean passwordSet = false; - if (password != null) { - Biff8EncryptionKey.setCurrentUserPassword(password); - passwordSet = true; - } - try { - initHslf(); - return (SlideShow) createHslfByNode.apply(root); - } finally { - if (passwordSet) { - Biff8EncryptionKey.setCurrentUserPassword(null); - } + return wp(FileMagic.OOXML, w -> w.create(root, password)); + } else { + return wp(FileMagic.OLE2, w -> w.create(root, password)); } } /** - * Creates the appropriate HSLFSlideShow / XMLSlideShow from + * Creates the appropriate HSLFSlideShow / XSLFSlideShow from * the given InputStream. * - *

Note that using an {@link InputStream} has a higher memory footprint + *

Your input stream MUST either support mark/reset, or + * be wrapped as a {@link BufferedInputStream}! + * Note that using an {@link InputStream} has a higher memory footprint * than using a {@link File}.

* *

Note that in order to properly release resources the @@ -170,20 +149,19 @@ public abstract class SlideShowFactory { * @return The created SlideShow * * @throws IOException if an error occurs while reading the data - * @throws EncryptedDocumentException If the SlideShow given is password protected + * @throws EncryptedDocumentException If the SlideShow given is password protected */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(InputStream inp) throws IOException, EncryptedDocumentException { + public static SlideShow create(InputStream inp) throws IOException, EncryptedDocumentException { return create(inp, null); } /** - * Creates the appropriate HSLFSlideShow / XMLSlideShow from + * Creates the appropriate HSLFSlideShow / XSLFSlideShow from * the given InputStream, which may be password protected. * - *

Note that using an {@link InputStream} has a higher memory footprint + *

Your input stream MUST either support mark/reset, or + * be wrapped as a {@link BufferedInputStream}! + * Note that using an {@link InputStream} has a higher memory footprint * than using a {@link File}.

* *

Note that in order to properly release resources the @@ -199,27 +177,32 @@ public abstract class SlideShowFactory { * @throws IOException if an error occurs while reading the data * @throws EncryptedDocumentException If the wrong password is given for a protected file */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(InputStream inp, String password) throws IOException, EncryptedDocumentException { + public static SlideShow create(InputStream inp, String password) throws IOException, EncryptedDocumentException { InputStream is = FileMagic.prepareToCheckMagic(inp); - FileMagic fm = FileMagic.valueOf(is); - - switch (fm) { - case OLE2: - POIFSFileSystem fs = new POIFSFileSystem(is); - return create(fs, password); - case OOXML: - initXslf(); - return (SlideShow) createXslfByStream.apply(is); - default: - throw new IOException("Your InputStream was neither an OLE2 stream, nor an OOXML stream"); + byte[] emptyFileCheck = new byte[1]; + is.mark(emptyFileCheck.length); + if (is.read(emptyFileCheck) < emptyFileCheck.length) { + throw new EmptyFileException(); + } + is.reset(); + + final FileMagic fm = FileMagic.valueOf(is); + if (FileMagic.OOXML == fm) { + return wp(fm, w -> w.create(is)); + } + + if (FileMagic.OLE2 != fm) { + throw new IOException("Can't open SlideShow - unsupported file type: "+fm); } + + POIFSFileSystem poifs = new POIFSFileSystem(is); + boolean isOOXML = poifs.getRoot().hasEntry(ENCRYPTION_INFO_ENTRY); + + return wp(isOOXML ? FileMagic.OOXML : fm, w -> w.create(poifs.getRoot(), password)); } /** - * Creates the appropriate HSLFSlideShow / XMLSlideShow from + * Creates the appropriate HSLFSlideShow / XSLFSlideShow from * the given File, which must exist and be readable. *

Note that in order to properly release resources the * SlideShow should be closed after use. @@ -231,15 +214,12 @@ public abstract class SlideShowFactory { * @throws IOException if an error occurs while reading the data * @throws EncryptedDocumentException If the SlideShow given is password protected */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(File file) throws IOException, EncryptedDocumentException { + public static SlideShow create(File file) throws IOException, EncryptedDocumentException { return create(file, null); } /** - * Creates the appropriate HSLFSlideShow / XMLSlideShow from + * Creates the appropriate HSLFSlideShow / XSLFSlideShow from * the given File, which must exist and be readable, and * may be password protected *

Note that in order to properly release resources the @@ -253,15 +233,12 @@ public abstract class SlideShowFactory { * @throws IOException if an error occurs while reading the data * @throws EncryptedDocumentException If the wrong password is given for a protected file */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(File file, String password) throws IOException, EncryptedDocumentException { + public static SlideShow create(File file, String password) throws IOException, EncryptedDocumentException { return create(file, password, false); } /** - * Creates the appropriate HSLFSlideShow / XMLSlideShow from + * Creates the appropriate HSLFSlideShow / XSLFSlideShow from * the given File, which must exist and be readable, and * may be password protected *

Note that in order to properly release resources the @@ -277,45 +254,39 @@ public abstract class SlideShowFactory { * @throws IOException if an error occurs while reading the data * @throws EncryptedDocumentException If the wrong password is given for a protected file */ - public static < - S extends Shape, - P extends TextParagraph - > SlideShow create(File file, String password, boolean readOnly) throws IOException, EncryptedDocumentException { + public static SlideShow create(File file, String password, boolean readOnly) throws IOException, EncryptedDocumentException { if (!file.exists()) { throw new FileNotFoundException(file.toString()); } - POIFSFileSystem fs = null; - try { - fs = new POIFSFileSystem(file, readOnly); - return create(fs, password); - } catch(OfficeXmlFileException e) { - IOUtils.closeQuietly(fs); - initXslf(); - return (SlideShow) createXslfByFile.apply(file, readOnly); - } catch(RuntimeException e) { - IOUtils.closeQuietly(fs); - throw e; + if (file.length() == 0) { + throw new EmptyFileException(); } - } - private static void initXslf() throws IOException { - if (createXslfByFile == null) { - initFactory("org.apache.poi.xslf.usermodel.XSLFSlideShowFactory", "poi-ooxml-*.jar"); + FileMagic fm = FileMagic.valueOf(file); + if (fm == FileMagic.OOXML) { + return wp(fm, w -> w.create(file, password, readOnly)); + } else if (fm == FileMagic.OLE2) { + final boolean ooxmlEnc; + try (POIFSFileSystem fs = new POIFSFileSystem(file, true)) { + ooxmlEnc = fs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY); + } + return wp(ooxmlEnc ? FileMagic.OOXML : fm, w -> w.create(file, password, readOnly)); } - } - private static void initHslf() throws IOException { - if (createHslfByPoifs == null) { - initFactory("org.apache.poi.hslf.usermodel.HSLFSlideShowFactory", "poi-scratchpad-*.jar"); - } + return null; } - private static void initFactory(String factoryClass, String jar) throws IOException { - try { - Class.forName(factoryClass, true, SlideShowFactory.class.getClassLoader()); - } catch (ClassNotFoundException e) { - throw new IOException(factoryClass+" not found - check if " + jar + " is on the classpath."); + + + private static SlideShow wp(FileMagic fm, SlideShowFactory.ProviderMethod fun) throws IOException { + + for (SlideShowProvider prov : SlideShowFactory.Singleton.INSTANCE.provider) { + if (prov.accepts(fm)) { + return fun.create(prov); + } } + throw new IOException("Your InputStream was neither an OLE2 stream, nor an OOXML stream " + + "or you haven't provide the poi-ooxml*.jar in the classpath/modulepath - FileMagic: "+fm); } } diff --git a/src/java/org/apache/poi/sl/usermodel/SlideShowProvider.java b/src/java/org/apache/poi/sl/usermodel/SlideShowProvider.java new file mode 100644 index 0000000000..3dbde3cde5 --- /dev/null +++ b/src/java/org/apache/poi/sl/usermodel/SlideShowProvider.java @@ -0,0 +1,42 @@ +/* ==================================================================== + 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.sl.usermodel; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.poi.poifs.filesystem.DirectoryNode; +import org.apache.poi.poifs.filesystem.FileMagic; + +public interface SlideShowProvider< + S extends Shape, + P extends TextParagraph +> { + boolean accepts(FileMagic fm); + + SlideShow create(); + + SlideShow create(InputStream inp) throws IOException; + + SlideShow create(InputStream inp, String password) throws IOException; + + SlideShow create(DirectoryNode root, String password) throws IOException; + + SlideShow create(File file, String password, boolean readOnly) throws IOException; +} diff --git a/src/java/org/apache/poi/ss/usermodel/WorkbookFactory.java b/src/java/org/apache/poi/ss/usermodel/WorkbookFactory.java index 25f5cde753..d9504fe63a 100644 --- a/src/java/org/apache/poi/ss/usermodel/WorkbookFactory.java +++ b/src/java/org/apache/poi/ss/usermodel/WorkbookFactory.java @@ -274,7 +274,7 @@ public final class WorkbookFactory { if (fm == FileMagic.OOXML) { return wp(fm, w -> w.create(file, password, readOnly)); } else if (fm == FileMagic.OLE2) { - boolean ooxmlEnc = false; + final boolean ooxmlEnc; try (POIFSFileSystem fs = new POIFSFileSystem(file, true)) { ooxmlEnc = fs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY); } diff --git a/src/multimodule/ooxml/java9/module-info.class b/src/multimodule/ooxml/java9/module-info.class index 0895d4b496..517b8bbe2c 100644 Binary files a/src/multimodule/ooxml/java9/module-info.class and b/src/multimodule/ooxml/java9/module-info.class differ diff --git a/src/multimodule/ooxml/java9/module-info.java b/src/multimodule/ooxml/java9/module-info.java index 876e6a3b1d..66928ffa24 100644 --- a/src/multimodule/ooxml/java9/module-info.java +++ b/src/multimodule/ooxml/java9/module-info.java @@ -28,8 +28,9 @@ module org.apache.poi.ooxml { requires java.desktop; requires java.security.jgss; - provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory; provides org.apache.poi.extractor.ExtractorProvider with org.apache.poi.ooxml.extractor.POIXMLExtractorFactory; + provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory; + provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.xslf.usermodel.XSLFSlideShowFactory; exports org.apache.poi.xwpf.extractor; exports org.apache.poi.xwpf.usermodel; @@ -79,7 +80,7 @@ module org.apache.poi.ooxml { opens org.apache.poi.openxml4j.opc to org.apache.poi.poi; - /* optional dependencies for xml signatures - you need to add a require entry your module-info + /* optional dependencies for xml signatures - you need to add a require entry to your module-info * or add them via the --add-modules JVM argument */ requires java.xml.crypto; requires static org.apache.santuario.xmlsec; diff --git a/src/multimodule/ooxml/test9/module-info.class b/src/multimodule/ooxml/test9/module-info.class index 7777b5f681..be87166834 100644 Binary files a/src/multimodule/ooxml/test9/module-info.class and b/src/multimodule/ooxml/test9/module-info.class differ diff --git a/src/multimodule/ooxml/test9/module-info.java b/src/multimodule/ooxml/test9/module-info.java index bd8a23a725..b41ae2b9b6 100644 --- a/src/multimodule/ooxml/test9/module-info.java +++ b/src/multimodule/ooxml/test9/module-info.java @@ -28,8 +28,9 @@ module org.apache.poi.ooxml { requires java.desktop; requires java.security.jgss; - provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory; provides org.apache.poi.extractor.ExtractorProvider with org.apache.poi.ooxml.extractor.POIXMLExtractorFactory; + provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory; + provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.xslf.usermodel.XSLFSlideShowFactory; exports org.apache.poi.xwpf.extractor; exports org.apache.poi.xwpf.usermodel; diff --git a/src/multimodule/poi/java9/module-info.class b/src/multimodule/poi/java9/module-info.class index ba2f2330ed..ab0e08c358 100644 Binary files a/src/multimodule/poi/java9/module-info.class and b/src/multimodule/poi/java9/module-info.class differ diff --git a/src/multimodule/poi/java9/module-info.java b/src/multimodule/poi/java9/module-info.java index 2995a21864..ea3f394035 100644 --- a/src/multimodule/poi/java9/module-info.java +++ b/src/multimodule/poi/java9/module-info.java @@ -27,8 +27,9 @@ module org.apache.poi.poi { /* needed for CleanerUtil */ requires jdk.unsupported; - uses org.apache.poi.ss.usermodel.WorkbookProvider; uses org.apache.poi.extractor.ExtractorProvider; + uses org.apache.poi.ss.usermodel.WorkbookProvider; + uses org.apache.poi.sl.usermodel.SlideShowProvider; provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.hssf.usermodel.HSSFWorkbookFactory; diff --git a/src/multimodule/poi/test9/module-info.class b/src/multimodule/poi/test9/module-info.class index 9010295aa0..2b43c43fa8 100644 Binary files a/src/multimodule/poi/test9/module-info.class and b/src/multimodule/poi/test9/module-info.class differ diff --git a/src/multimodule/poi/test9/module-info.java b/src/multimodule/poi/test9/module-info.java index add8071309..9e5bc0a110 100644 --- a/src/multimodule/poi/test9/module-info.java +++ b/src/multimodule/poi/test9/module-info.java @@ -27,8 +27,9 @@ module org.apache.poi.poi { /* needed for CleanerUtil */ requires jdk.unsupported; - uses org.apache.poi.ss.usermodel.WorkbookProvider; uses org.apache.poi.extractor.ExtractorProvider; + uses org.apache.poi.ss.usermodel.WorkbookProvider; + uses org.apache.poi.sl.usermodel.SlideShowProvider; provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.hssf.usermodel.HSSFWorkbookFactory; provides org.apache.poi.extractor.ExtractorProvider with org.apache.poi.extractor.MainExtractorFactory; diff --git a/src/multimodule/scratchpad/java9/module-info.class b/src/multimodule/scratchpad/java9/module-info.class index 5e04b3dec9..8697888d28 100644 Binary files a/src/multimodule/scratchpad/java9/module-info.class and b/src/multimodule/scratchpad/java9/module-info.class differ diff --git a/src/multimodule/scratchpad/java9/module-info.java b/src/multimodule/scratchpad/java9/module-info.java index 717730fdd4..b936858c70 100644 --- a/src/multimodule/scratchpad/java9/module-info.java +++ b/src/multimodule/scratchpad/java9/module-info.java @@ -21,6 +21,7 @@ module org.apache.poi.scratchpad { requires commons.math3; provides org.apache.poi.extractor.ExtractorProvider with org.apache.poi.extractor.ole2.OLE2ScratchpadExtractorFactory; + provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.hslf.usermodel.HSLFSlideShowFactory; exports org.apache.poi.hmef; exports org.apache.poi.hmef.dev; diff --git a/src/multimodule/scratchpad/test9/module-info.class b/src/multimodule/scratchpad/test9/module-info.class index 489d1d1ab9..4ee1e56a65 100644 Binary files a/src/multimodule/scratchpad/test9/module-info.class and b/src/multimodule/scratchpad/test9/module-info.class differ diff --git a/src/multimodule/scratchpad/test9/module-info.java b/src/multimodule/scratchpad/test9/module-info.java index db69fd4e8f..cb0691b9a1 100644 --- a/src/multimodule/scratchpad/test9/module-info.java +++ b/src/multimodule/scratchpad/test9/module-info.java @@ -21,6 +21,7 @@ module org.apache.poi.scratchpad { requires commons.math3; provides org.apache.poi.extractor.ExtractorProvider with org.apache.poi.extractor.ole2.OLE2ScratchpadExtractorFactory; + provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.hslf.usermodel.HSLFSlideShowFactory; exports org.apache.poi.hmef; exports org.apache.poi.hmef.dev; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideShowFactory.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideShowFactory.java index 548cdc7a08..929b000bbb 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideShowFactory.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideShowFactory.java @@ -25,40 +25,81 @@ import org.apache.poi.EncryptedDocumentException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageAccess; -import org.apache.poi.sl.usermodel.SlideShowFactory; +import org.apache.poi.poifs.filesystem.DirectoryNode; +import org.apache.poi.poifs.filesystem.DocumentFactoryHelper; +import org.apache.poi.poifs.filesystem.FileMagic; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.sl.usermodel.SlideShowProvider; import org.apache.poi.util.Internal; @Internal -public class XSLFSlideShowFactory extends SlideShowFactory { +public class XSLFSlideShowFactory implements SlideShowProvider { - static { - SlideShowFactory.createXslfByFile = XSLFSlideShowFactory::createSlideShow; - SlideShowFactory.createXslfByStream = XSLFSlideShowFactory::createSlideShow; + @Override + public boolean accepts(FileMagic fm) { + return fm == FileMagic.OOXML; } /** - * Creates a XMLSlideShow from the given OOXML Package. - * This is a convenience method to go along the create-methods of the super class. + * Create a new empty SlideShow + * + * @return The created SlideShow + */ + @Override + public XMLSlideShow create() { + return new XMLSlideShow(); + } + + @Override + public XMLSlideShow create(DirectoryNode root, String password) throws IOException { + try (InputStream stream = DocumentFactoryHelper.getDecryptedStream(root, password)) { + return create(stream); + } finally { + // as we processed the full stream already, we can close the filesystem here + // otherwise file handles are leaked + root.getFileSystem().close(); + } + } + + @Override + public XMLSlideShow create(InputStream inp, String password) throws IOException { + InputStream bufInp = FileMagic.prepareToCheckMagic(inp); + FileMagic fm = FileMagic.valueOf(bufInp); + + if (fm == FileMagic.OLE2) { + try (POIFSFileSystem poifs = new POIFSFileSystem(bufInp); + InputStream stream = DocumentFactoryHelper.getDecryptedStream(poifs.getRoot(), password)) { + return create(stream); + } + } + + if (fm == FileMagic.OOXML) { + return create(bufInp); + } + + return null; + } + + /** + * Creates a XMLSlideShow from the given InputStream * *

Note that in order to properly release resources the - * SlideShow should be closed after use.

+ * SlideShow should be closed after use.

* - * @param pkg The {@link OPCPackage} opened for reading data. + * @param stream The {@link InputStream} to read data from. * - * @return The created SlideShow + * @return The created SlideShow * - * @throws IOException if an error occurs while reading the data + * @throws IOException if an error occurs while reading the data */ - public static XMLSlideShow create(OPCPackage pkg) throws IOException { + @SuppressWarnings("resource") + @Override + public XMLSlideShow create(InputStream stream) throws IOException { try { - return new XMLSlideShow(pkg); - } catch (IllegalArgumentException ioe) { - // ensure that file handles are closed (use revert() to not re-write the file) - pkg.revert(); - //pkg.close(); - - // rethrow exception - throw ioe; + OPCPackage pkg = OPCPackage.open(stream); + return createSlideShow(pkg); + } catch (InvalidFormatException e) { + throw new IOException(e); } } @@ -77,7 +118,7 @@ public class XSLFSlideShowFactory extends SlideShowFactory { public static XMLSlideShow createSlideShow(OPCPackage pkg) throws IOException { try { return new XMLSlideShow(pkg); - } catch (IllegalArgumentException ioe) { + } catch (RuntimeException ioe) { // ensure that file handles are closed (use revert() to not re-write the file) pkg.revert(); //pkg.close(); @@ -89,7 +130,7 @@ public class XSLFSlideShowFactory extends SlideShowFactory { /** * Creates the XMLSlideShow from the given File, which must exist and be readable. - *

Note that in order to properly release resources theSlideShow should be closed after use. + *

Note that in order to properly release resources the SlideShow should be closed after use. * * @param file The file to read data from. * @param readOnly If the SlideShow should be opened in read-only mode to avoid writing back @@ -101,36 +142,21 @@ public class XSLFSlideShowFactory extends SlideShowFactory { * @throws EncryptedDocumentException If the wrong password is given for a protected file */ @SuppressWarnings("resource") - public static XMLSlideShow createSlideShow(File file, boolean readOnly) - throws IOException { - try { - OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE); - return createSlideShow(pkg); - } catch (InvalidFormatException e) { - throw new IOException(e); + public XMLSlideShow create(File file, String password, boolean readOnly) throws IOException { + FileMagic fm = FileMagic.valueOf(file); + + if (fm == FileMagic.OLE2) { + try (POIFSFileSystem poifs = new POIFSFileSystem(file, true); + InputStream stream = DocumentFactoryHelper.getDecryptedStream(poifs.getRoot(), password)) { + return create(stream); + } } - } - /** - * Creates a XMLSlideShow from the given InputStream - * - *

Note that in order to properly release resources the - * SlideShow should be closed after use.

- * - * @param stream The {@link InputStream} to read data from. - * - * @return The created SlideShow - * - * @throws IOException if an error occurs while reading the data - */ - @SuppressWarnings("resource") - public static XMLSlideShow createSlideShow(InputStream stream) throws IOException { try { - OPCPackage pkg = OPCPackage.open(stream); + OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE); return createSlideShow(pkg); } catch (InvalidFormatException e) { throw new IOException(e); } } - } diff --git a/src/resources/ooxml/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider b/src/resources/ooxml/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider new file mode 100644 index 0000000000..f4251abe27 --- /dev/null +++ b/src/resources/ooxml/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider @@ -0,0 +1,18 @@ +# ==================================================================== +# 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. +# ==================================================================== + +org.apache.poi.xslf.usermodel.XSLFSlideShowFactory \ No newline at end of file diff --git a/src/resources/scratchpad/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider b/src/resources/scratchpad/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider new file mode 100644 index 0000000000..1fcb1ec7c7 --- /dev/null +++ b/src/resources/scratchpad/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider @@ -0,0 +1,18 @@ +# ==================================================================== +# 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. +# ==================================================================== + +org.apache.poi.hslf.usermodel.HSLFSlideShowFactory \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java b/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java index 16711d0b11..d0e0f88e81 100644 --- a/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java +++ b/src/scratchpad/src/org/apache/poi/extractor/ole2/OLE2ScratchpadExtractorFactory.java @@ -30,9 +30,7 @@ import org.apache.poi.extractor.POIOLE2TextExtractor; import org.apache.poi.extractor.POITextExtractor; import org.apache.poi.hdgf.extractor.VisioTextExtractor; import org.apache.poi.hpbf.extractor.PublisherTextExtractor; -import org.apache.poi.hslf.usermodel.HSLFShape; import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.usermodel.HSLFTextParagraph; import org.apache.poi.hsmf.MAPIMessage; import org.apache.poi.hsmf.datatypes.AttachmentChunks; import org.apache.poi.hsmf.extractor.OutlookTextExtractor; @@ -102,7 +100,7 @@ public class OLE2ScratchpadExtractorFactory implements ExtractorProvider { } if (poifsDir.hasEntry(HSLFSlideShow.POWERPOINT_DOCUMENT)) { - return new SlideShowExtractor(SlideShowFactory.create(poifsDir)); + return new SlideShowExtractor<>((HSLFSlideShow)SlideShowFactory.create(poifsDir)); } if (poifsDir.hasEntry("VisioDocument")) { diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowFactory.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowFactory.java index 42db16482e..936eae064e 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowFactory.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowFactory.java @@ -17,11 +17,16 @@ package org.apache.poi.hslf.usermodel; +import java.io.File; import java.io.IOException; +import java.io.InputStream; +import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; import org.apache.poi.poifs.filesystem.DirectoryNode; +import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.sl.usermodel.SlideShowFactory; +import org.apache.poi.sl.usermodel.SlideShowProvider; import org.apache.poi.util.Internal; /** @@ -30,11 +35,20 @@ import org.apache.poi.util.Internal; */ @SuppressWarnings("unused") @Internal -public class HSLFSlideShowFactory extends SlideShowFactory { +public class HSLFSlideShowFactory implements SlideShowProvider { - static { - SlideShowFactory.createHslfByNode = HSLFSlideShowFactory::createSlideShow; - SlideShowFactory.createHslfByPoifs = HSLFSlideShowFactory::createSlideShow; + @Override + public boolean accepts(FileMagic fm) { + return FileMagic.OLE2 == fm; + } + + /** + * Create a new empty SlideShow + * + * @return The created SlideShow + */ + public HSLFSlideShow create() { + return new HSLFSlideShow(); } /** @@ -51,7 +65,45 @@ public class HSLFSlideShowFactory extends SlideShowFactory { * Note that in order to properly release resources the * SlideShow should be closed after use. */ - public static HSLFSlideShow createSlideShow(final DirectoryNode root) throws IOException { - return new HSLFSlideShow(root); + public HSLFSlideShow create(final DirectoryNode root, String password) throws IOException { + boolean passwordSet = false; + if (password != null) { + Biff8EncryptionKey.setCurrentUserPassword(password); + passwordSet = true; + } + try { + return new HSLFSlideShow(root); + } finally { + if (passwordSet) { + Biff8EncryptionKey.setCurrentUserPassword(null); + } + } + } + + @Override + public HSLFSlideShow create(InputStream inp) throws IOException { + return create(inp, null); + } + + @Override + public HSLFSlideShow create(InputStream inp, String password) throws IOException { + POIFSFileSystem fs = new POIFSFileSystem(inp); + return create(fs.getRoot(), password); + } + + @Override + public HSLFSlideShow create(File file, String password, boolean readOnly) throws IOException { + boolean passwordSet = false; + if (password != null) { + Biff8EncryptionKey.setCurrentUserPassword(password); + passwordSet = true; + } + try { + return new HSLFSlideShow(new POIFSFileSystem(file, readOnly)); + } finally { + if (passwordSet) { + Biff8EncryptionKey.setCurrentUserPassword(null); + } + } } } diff --git a/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java b/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java index 5d53b4bd62..6158c9de63 100644 --- a/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java +++ b/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java @@ -160,8 +160,9 @@ public abstract class BaseTestSlideShow< @Test public void shapeAndSlideName() throws IOException { final String file = "SampleShow.ppt"+(getClass().getSimpleName().contains("XML")?"x":""); + //noinspection unchecked try (final InputStream is = slTests.openResourceAsStream(file); - final SlideShow ppt = SlideShowFactory.create(is)) { + final SlideShow ppt = (SlideShow)SlideShowFactory.create(is)) { final List shapes1 = ppt.getSlides().get(0).getShapes(); assertEquals("The Title", shapes1.get(0).getShapeName()); assertEquals("Another Subtitle", shapes1.get(1).getShapeName()); diff --git a/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShowFactory.java b/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShowFactory.java index d62d787d94..345bb7906e 100644 --- a/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShowFactory.java +++ b/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShowFactory.java @@ -98,7 +98,7 @@ public abstract class BaseTestSlideShowFactory { // from protected POIFS if (protectedFile.endsWith(".ppt") || protectedFile.endsWith(".pptx")) { POIFSFileSystem poifs = new POIFSFileSystem(fromFile(protectedFile)); - ss = SlideShowFactory.create(poifs, password); + ss = SlideShowFactory.create(poifs.getRoot(), password); assertNotNull(ss); poifs.close(); assertCloseDoesNotModifyFile(protectedFile, ss); @@ -172,13 +172,13 @@ public abstract class BaseTestSlideShowFactory { assertArrayEquals(filename + " sample file was modified as a result of closing the slideshow", before, after); } catch (AssertionError e) { - // if the file after closing is different, then re-set - // the file to the state before in order to not have a dirty SCM + // if the file after closing is different, then re-set + // the file to the state before in order to not have a dirty SCM // working tree when running this test try (FileOutputStream str = new FileOutputStream(_slTests.getFile(filename))) { str.write(before); } - + throw e; } }