From 5caf8e109b8fac9341091b7a7bc94a29db01c267 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Fri, 14 Aug 2020 19:08:42 +0000 Subject: [PATCH] #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 --- .../poi/sl/usermodel/SlideShowFactory.java | 237 ++++++++---------- .../poi/sl/usermodel/SlideShowProvider.java | 42 ++++ .../poi/ss/usermodel/WorkbookFactory.java | 2 +- src/multimodule/ooxml/java9/module-info.class | Bin 2715 -> 2828 bytes src/multimodule/ooxml/java9/module-info.java | 5 +- src/multimodule/ooxml/test9/module-info.class | Bin 3584 -> 3697 bytes src/multimodule/ooxml/test9/module-info.java | 3 +- src/multimodule/poi/java9/module-info.class | Bin 3169 -> 3222 bytes src/multimodule/poi/java9/module-info.java | 3 +- src/multimodule/poi/test9/module-info.class | Bin 3296 -> 3349 bytes src/multimodule/poi/test9/module-info.java | 3 +- .../scratchpad/java9/module-info.class | Bin 2219 -> 2332 bytes .../scratchpad/java9/module-info.java | 1 + .../scratchpad/test9/module-info.class | Bin 2393 -> 2506 bytes .../scratchpad/test9/module-info.java | 1 + .../xslf/usermodel/XSLFSlideShowFactory.java | 118 +++++---- ....apache.poi.sl.usermodel.SlideShowProvider | 18 ++ ....apache.poi.sl.usermodel.SlideShowProvider | 18 ++ .../ole2/OLE2ScratchpadExtractorFactory.java | 4 +- .../hslf/usermodel/HSLFSlideShowFactory.java | 64 ++++- .../poi/sl/usermodel/BaseTestSlideShow.java | 3 +- .../usermodel/BaseTestSlideShowFactory.java | 8 +- 22 files changed, 331 insertions(+), 199 deletions(-) create mode 100644 src/java/org/apache/poi/sl/usermodel/SlideShowProvider.java create mode 100644 src/resources/ooxml/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider create mode 100644 src/resources/scratchpad/META-INF/services/org.apache.poi.sl.usermodel.SlideShowProvider 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 0895d4b496877476aabecd9fc83cf487727451ee..517b8bbe2c795ea4aaa15af69477f66ea30d1e4d 100644 GIT binary patch delta 180 zcmbO&+9Sqw>ff$?3=9mW3|$+!lsG0&<ff$?3=9mW3~d{^lsG0&=g?uHvj`ff$?3=9mW3|lsGJ?3K6n(WUZIk|vam}NC1gXv^L7SYLbxD}Y$8P-mI z&1J~4o{_QP`6;P6`oTGw zDXGC3`Q-sc`DH+65j(?XMh2tF-t4lP`VqlCZg2%|iOD7TMU@Q<42(dxKma2HGXn#Y b+2#w}%1pw{3@dff$?3=9mW3>!9bJ?5Gm!L84-nvub9vLT!7KEi^ z>KEtemlmfM<>sfP=I96KWTvDBXXKX$6y=uznMLdj^Ct^%nXxPcYMeZeQDSlumj>gF d&D~sw8AX{HW-!cRn8UyXBpDgz0eOrJ3jkwVDQW-! delta 86 zcmbOx`A~xE)W2Q(7#J8#85V5hTE;o~0jECW?8)mm^;zaJG8j${WD=QN!@@N=g-euW pJ|lzfn@-y{|bM#A#Q;Tx*Q&MyEgL5)dQiC({%L9t?%Ye)xc82AQ42F|8vWQOZ=8|Jv lIe8VAGvk-d@3`(WiZU}SU|7Vkgnn9c@CTFDT7vyK^7w71g7N-{F z=BK3Q=m+OyrlbaE3anGxWN@nwqciIjM^N|?#sx_ P#8AM%$WX*k0wl`-T8Sh} delta 53 zcmbOuv|5ns)W2Q(7#J8#8A>*CS+a{XFfcFzxe&m}zzpPuY(B*9%gD~iPym!F0svA~ B3H$&6 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 489d1d1ab92275167d33a3cb01f534a3e45de336..4ee1e56a657302645cc8efca30f6ca4d0a5e5f84 100644 GIT binary patch delta 166 zcmca9bV``()W2Q(7#J8#8Jae7ZDy}$XQ*dn(9JJO*H0`+OwLHvFUZf-FV4{~Elw@U z%}+_q(GSkaOi2yS$S)5l$}a;li`W?&85xYwv}6?Lq#ld{c<))W2Q(7#J8#8R|B2ZDyaW!6D4pvDt>Bk&&H|p^AZ#p#}g3WD61i 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; } } -- 2.39.5