+ * Note that in order to properly release resources the + * Workbook should be closed after use. + */ + public static HSSFWorkbook createWorkbook(final NPOIFSFileSystem fs) throws IOException { + return new HSSFWorkbook(fs); + } + + /** + * Creates a HSSFWorkbook from the given DirectoryNode
+ * Note that in order to properly release resources the + * Workbook should be closed after use. + */ + public static HSSFWorkbook createWorkbook(final DirectoryNode root) throws IOException { + return new HSSFWorkbook(root, true); + } +} diff --git a/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java b/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java index 5f75258b9..31c669cf0 100644 --- a/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java +++ b/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java @@ -189,7 +189,7 @@ public class SlideShowFactory { case OOXML: return createXSLFSlideShow(is); default: - throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream"); + throw new IOException("Your InputStream was neither an OLE2 stream, nor an OOXML stream"); } } @@ -314,6 +314,8 @@ public class SlideShowFactory { throw (EncryptedDocumentException)t; } else if (t instanceof OldFileFormatException) { throw (OldFileFormatException)t; + } else if (t instanceof RuntimeException) { + throw (RuntimeException)t; } else { throw new IOException(t); } diff --git a/src/java/org/apache/poi/ss/usermodel/ObjectData.java b/src/java/org/apache/poi/ss/usermodel/ObjectData.java index d157dba53..3d21b1a8d 100644 --- a/src/java/org/apache/poi/ss/usermodel/ObjectData.java +++ b/src/java/org/apache/poi/ss/usermodel/ObjectData.java @@ -62,4 +62,8 @@ public interface ObjectData extends SimpleShape { * @return the preview picture */ PictureData getPictureData(); + + default String getContentType() { + return "binary/octet-stream"; + } } 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 501132c00..c62e24134 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideShowFactory.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideShowFactory.java @@ -31,6 +31,33 @@ import org.apache.poi.util.Internal; @Internal public class XSLFSlideShowFactory extends SlideShowFactory { + /** + * Creates a XMLSlideShow from the given OOXML Package. + * This is a convenience method to go along the create-methods of the super class. + * + *
Note that in order to properly release resources the + * SlideShow should be closed after use.
+ * + * @param pkg The {@link OPCPackage} opened for reading data. + * + * @return The created SlideShow + * + * @throws IOException if an error occurs while reading the data + * @throws InvalidFormatException + */ + public static XMLSlideShow create(OPCPackage pkg) 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; + } + } + /** * Creates a XMLSlideShow from the given OOXML Package * diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java index c20d8d44c..0544800e6 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java @@ -23,8 +23,8 @@ import java.io.InputStream; import javax.xml.namespace.QName; -import org.apache.poi.POIXMLDocumentPart; -import org.apache.poi.POIXMLException; +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ooxml.POIXMLException; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.poifs.filesystem.DirectoryEntry; @@ -202,4 +202,9 @@ public class XSSFObjectData extends XSSFSimpleShape implements ObjectData { cur.dispose(); } } + + @Override + public String getContentType() { + return getObjectPart().getContentType(); + } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbookFactory.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbookFactory.java new file mode 100644 index 000000000..4bb6acc59 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbookFactory.java @@ -0,0 +1,134 @@ +/* ==================================================================== + 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.xssf.usermodel; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +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.openxml4j.opc.ZipPackage; +import org.apache.poi.ss.usermodel.WorkbookFactory; + +public class XSSFWorkbookFactory extends WorkbookFactory { + + /** + * Creates a XSSFWorkbook from the given OOXML Package. + * This is a convenience method to go along the create-methods of the super class. + * + *Note that in order to properly release resources the + * Workbook should be closed after use.
+ * + * @param pkg The {@link OPCPackage} opened for reading data. + * + * @return The created Workbook + * + * @throws IOException if an error occurs while reading the data + * @throws InvalidFormatException + */ + public static XSSFWorkbook create(OPCPackage pkg) throws IOException { + return createWorkbook(pkg); + } + + /** + * Creates a XSSFWorkbook from the given OOXML Package + * + *Note that in order to properly release resources the + * Workbook should be closed after use.
+ * + * @param pkg The {@link ZipPackage} opened for reading data. + * + * @return The created Workbook + * + * @throws IOException if an error occurs while reading the data + * @throws InvalidFormatException + */ + public static XSSFWorkbook createWorkbook(ZipPackage pkg) throws IOException { + return createWorkbook((OPCPackage)pkg); + } + + /** + * Creates a XSSFWorkbook from the given OOXML Package + * + *Note that in order to properly release resources the + * Workbook should be closed after use.
+ * + * @param pkg The {@link OPCPackage} opened for reading data. + * + * @return The created Workbook + * + * @throws IOException if an error occurs while reading the data + * @throws InvalidFormatException + */ + public static XSSFWorkbook createWorkbook(OPCPackage pkg) throws IOException { + try { + return new XSSFWorkbook(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; + } + } + + /** + * Creates the XSSFWorkbook from the given File, which must exist and be readable. + *Note that in order to properly release resources the Workbook should be closed after use. + * + * @param file The file to read data from. + * @param readOnly If the Workbook should be opened in read-only mode to avoid writing back + * changes when the document is closed. + * + * @return The created Workbook + * + * @throws IOException if an error occurs while reading the data + * @throws EncryptedDocumentException If the wrong password is given for a protected file + */ + @SuppressWarnings("resource") + public static XSSFWorkbook createWorkbook(File file, boolean readOnly) + throws IOException, InvalidFormatException { + OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE); + return createWorkbook(pkg); + } + + /** + * Creates a XSSFWorkbook from the given InputStream + * + *
Note that in order to properly release resources the + * Workbook should be closed after use.
+ * + * @param stream The {@link InputStream} to read data from. + * + * @return The created Workbook + * + * @throws IOException if an error occurs while reading the data + * @throws InvalidFormatException + */ + @SuppressWarnings("resource") + public static XSSFWorkbook createWorkbook(InputStream stream) throws IOException, InvalidFormatException { + OPCPackage pkg = OPCPackage.open(stream); + return createWorkbook(pkg); + } + + +} diff --git a/src/ooxml/testcases/org/apache/poi/ss/TestWorkbookFactory.java b/src/ooxml/testcases/org/apache/poi/ss/TestWorkbookFactory.java index 4b77e96be..645a28bf3 100644 --- a/src/ooxml/testcases/org/apache/poi/ss/TestWorkbookFactory.java +++ b/src/ooxml/testcases/org/apache/poi/ss/TestWorkbookFactory.java @@ -39,6 +39,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook; 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.xssf.usermodel.XSSFWorkbookFactory; import org.junit.Test; public final class TestWorkbookFactory { @@ -107,7 +108,7 @@ public final class TestWorkbookFactory { assertCloseDoesNotModifyFile(xls, wb); // Package -> xssf - wb = WorkbookFactory.create( + wb = XSSFWorkbookFactory.create( OPCPackage.open( HSSFTestDataSamples.openSampleFileStream(xlsx)) ); @@ -182,7 +183,7 @@ public final class TestWorkbookFactory { stream.close(); } fail(); - } catch(InvalidFormatException e) { + } catch(IOException e) { // Good } final byte[] after = HSSFTestDataSamples.getTestDataFileContent(txt); 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 c6c25f3f6..8d7357783 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java @@ -46,10 +46,10 @@ import java.util.TreeMap; import org.apache.poi.EncryptedDocumentException; import org.apache.poi.POIDataSamples; -import org.apache.poi.POIXMLDocumentPart; -import org.apache.poi.POIXMLDocumentPart.RelationPart; -import org.apache.poi.POIXMLException; -import org.apache.poi.POIXMLProperties; +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart; +import org.apache.poi.ooxml.POIXMLException; +import org.apache.poi.ooxml.POIXMLProperties; import org.apache.poi.common.usermodel.HyperlinkType; import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.hssf.HSSFTestDataSamples; @@ -1459,10 +1459,10 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { } /** - * Password Protected .xlsx files should give a helpful - * error message when called via WorkbookFactory with no password + * Password Protected .xlsx files are now (as of 4.0.0) tested for the default password + * when opened via WorkbookFactory, so there's no EncryptedDocumentException thrown anymore */ - @Test(expected = EncryptedDocumentException.class) + @Test public void bug55692_poifs() throws IOException { // Via a POIFSFileSystem try (POIFSFileSystem fsP = new POIFSFileSystem( @@ -1951,7 +1951,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { // Workbook Factory gives helpful error on package try { - WorkbookFactory.create(pkg).close(); + XSSFWorkbookFactory.create(pkg).close(); fail(".xlsb files not supported"); } catch (XLSBUnsupportedException e) { // Good, detected and warned diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java index e5b0fac89..a29bd305a 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java @@ -502,18 +502,4 @@ public class AbstractWordUtils return loadDoc( poifsFileSystem.getRoot() ); } - static String substringBeforeLast( String str, String separator ) - { - if ( isEmpty( str ) || isEmpty( separator ) ) - { - return str; - } - int pos = str.lastIndexOf( separator ); - if ( pos == -1 ) - { - return str; - } - return str.substring( 0, pos ); - } - } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/DefaultFontReplacer.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/DefaultFontReplacer.java index c7392c4e3..b9845fd34 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/converter/DefaultFontReplacer.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/DefaultFontReplacer.java @@ -23,37 +23,33 @@ public class DefaultFontReplacer implements FontReplacer { public Triplet update( Triplet original ) { - if ( AbstractWordUtils.isNotEmpty( original.fontName ) ) + if ( isNotEmpty( original.fontName ) ) { String fontName = original.fontName; if ( fontName.endsWith( " Regular" ) ) - fontName = AbstractWordUtils.substringBeforeLast( fontName, - " Regular" ); + fontName = substringBeforeLast( fontName, " Regular" ); if ( fontName .endsWith( " \u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439" ) ) - fontName = AbstractWordUtils - .substringBeforeLast( fontName, - " \u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439" ) + fontName = substringBeforeLast( fontName, + " \u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439" ) + " Bold"; if ( fontName .endsWith( " \u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439 \u041A\u0443\u0440\u0441\u0438\u0432" ) ) - fontName = AbstractWordUtils - .substringBeforeLast( - fontName, - " \u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439 \u041A\u0443\u0440\u0441\u0438\u0432" ) + fontName = substringBeforeLast( + fontName, + " \u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439 \u041A\u0443\u0440\u0441\u0438\u0432" ) + " Bold Italic"; if ( fontName.endsWith( " \u041A\u0443\u0440\u0441\u0438\u0432" ) ) - fontName = AbstractWordUtils.substringBeforeLast( fontName, - " \u041A\u0443\u0440\u0441\u0438\u0432" ) + " Italic"; + fontName = substringBeforeLast( fontName, " \u041A\u0443\u0440\u0441\u0438\u0432" ) + " Italic"; original.fontName = fontName; } - if ( AbstractWordUtils.isNotEmpty( original.fontName ) ) + if ( isNotEmpty( original.fontName ) ) { if ( "Times Regular".equals( original.fontName ) || "Times-Regular".equals( original.fontName ) @@ -88,4 +84,30 @@ public class DefaultFontReplacer implements FontReplacer return original; } + + private static boolean isEmpty( String str ) + { + return str == null || str.length() == 0; + } + + private static boolean isNotEmpty( String str ) + { + return !isEmpty( str ); + } + + + private static String substringBeforeLast( String str, String separator ) + { + if ( isEmpty( str ) || isEmpty( separator ) ) + { + return str; + } + int pos = str.lastIndexOf( separator ); + if ( pos == -1 ) + { + return str; + } + return str.substring( 0, pos ); + } + }