Author: fanningpj
Date: Thu Oct 26 18:09:38 2023
New Revision: 1913359

URL: http://svn.apache.org/viewvc?rev=1913359&view=rev
Log:
[bug-67579] add new XSSFWorkbook constructor

Added:
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/NoCloseInputStream.java
   (with props)
Modified:
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/util/PackageHelper.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
    
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/util/PackageHelper.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/util/PackageHelper.java?rev=1913359&r1=1913358&r2=1913359&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/util/PackageHelper.java 
(original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/util/PackageHelper.java 
Thu Oct 26 18:09:38 2023
@@ -43,20 +43,25 @@ import org.apache.poi.util.Removal;
  */
 public final class PackageHelper {
 
-    public static OPCPackage open(InputStream is) throws IOException {
-        return open(is, false);
+    /**
+     * @param stream The InputStream to read from - which is closed when it is 
read
+     * @return OPCPackage
+     * @throws IOException If reading data from the stream fails
+     */
+    public static OPCPackage open(InputStream stream) throws IOException {
+        return open(stream, false);
     }
 
     /**
      * @param stream The InputStream to read from
-     * @param closeStream whether to close the stream (default is false)
-     * @since POI 5.2.0
+     * @param closeStream whether to close the stream
      * @return OPCPackage
      * @throws IOException If reading data from the stream fails
+     * @since POI 5.2.0
      */
     public static OPCPackage open(InputStream stream, boolean closeStream) 
throws IOException {
         try {
-            return OPCPackage.open(stream);
+            return OPCPackage.open(stream, closeStream);
         } catch (InvalidFormatException e){
             throw new POIXMLException(e);
         } finally {

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java?rev=1913359&r1=1913358&r2=1913359&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java 
(original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/OPCPackage.java 
Thu Oct 26 18:09:38 2023
@@ -329,6 +329,38 @@ public abstract class OPCPackage impleme
     }
 
     /**
+     * Open a package.
+     *
+     * Note - uses quite a bit more memory than {@link #open(String)}, which
+     * doesn't need to hold the whole zip file in memory, and can take 
advantage
+     * of native methods
+     *
+     * @param in
+     *            The InputStream to read the package from.
+     * @param closeStream
+     *            Whether to close the input stream.
+     * @return A PackageBase object
+     *
+     * @throws InvalidFormatException
+     *              Throws if the specified file exist and is not valid.
+     * @throws IOException If reading the stream fails
+     * @since POI 5.2.5
+     */
+    public static OPCPackage open(InputStream in, boolean closeStream) throws 
InvalidFormatException,
+            IOException {
+        OPCPackage pack = new ZipPackage(in, PackageAccess.READ_WRITE, 
closeStream);
+        try {
+            if (pack.partList == null) {
+                pack.getParts();
+            }
+        } catch (InvalidFormatException | RuntimeException e) {
+            IOUtils.closeQuietly(pack);
+            throw e;
+        }
+        return pack;
+    }
+
+    /**
      * Opens a package if it exists, else it creates one.
      *
      * @param file

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java?rev=1913359&r1=1913358&r2=1913359&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java 
(original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java 
Thu Oct 26 18:09:38 2023
@@ -115,7 +115,7 @@ public final class ZipPackage extends OP
 
     /**
      * Constructor. Opens a Zip based Open XML document from
-     *  an InputStream.
+     *  an InputStream. The InputStream is closed.
      *
      * @param in
      *            Zip input stream to load.
@@ -133,6 +133,30 @@ public final class ZipPackage extends OP
             this.zipArchive = new ZipInputStreamZipEntrySource(zis);
         }
     }
+
+    /**
+     * Constructor. Opens a Zip based Open XML document from
+     *  an InputStream. The InputStream is closed.
+     *
+     * @param in
+     *            Zip input stream to load.
+     * @param access
+     *            The package access mode.
+     * @param closeStream
+     *            Whether to close the input stream.
+     * @throws IllegalArgumentException
+     *             If the specified input stream is not an instance of
+     *             ZipInputStream.
+     * @throws IOException
+     *            if input stream cannot be opened, read, or closed
+     * @since POI 5.2.5
+     */
+    ZipPackage(InputStream in, PackageAccess access, boolean closeStream) 
throws IOException {
+        super(access);
+        try (ZipArchiveThresholdInputStream zis = ZipHelper.openZipStream(in, 
closeStream)) {
+            this.zipArchive = new ZipInputStreamZipEntrySource(zis);
+        }
+    }
 
     /**
      * Constructor. Opens a Zip based Open XML document from a file.

Added: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/NoCloseInputStream.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/NoCloseInputStream.java?rev=1913359&view=auto
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/NoCloseInputStream.java
 (added)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/NoCloseInputStream.java
 Thu Oct 26 18:09:38 2023
@@ -0,0 +1,33 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import org.apache.poi.util.Internal;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+
+@Internal
+final class NoCloseInputStream extends FilterInputStream {
+    NoCloseInputStream(InputStream stream) {
+        super(stream);
+    }
+
+    @Override
+    public void close() {}
+}

Propchange: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/NoCloseInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java?rev=1913359&r1=1913358&r2=1913359&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
 Thu Oct 26 18:09:38 2023
@@ -163,20 +163,33 @@ public final class ZipHelper {
     }
 
     /**
-     * Opens the specified stream as a secure zip
+     * Opens the specified stream as a secure zip. Closes the Input Stream.
      *
-     * @param stream
-     *            The stream to open.
+     * @param stream The stream to open.
      * @return The zip stream freshly open.
      */
     @SuppressWarnings("resource")
     public static ZipArchiveThresholdInputStream openZipStream(InputStream 
stream) throws IOException {
+        return openZipStream(stream, true);
+    }
+
+    /**
+     * Opens the specified stream as a secure zip. Closes the Input Stream.
+     *
+     * @param stream The stream to open.
+     * @param closeStream whether to close the stream
+     * @return The zip stream freshly open.
+     */
+    @SuppressWarnings("resource")
+    public static ZipArchiveThresholdInputStream openZipStream(
+            final InputStream stream, final boolean closeStream) throws 
IOException {
         // Peek at the first few bytes to sanity check
         InputStream checkedStream = FileMagic.prepareToCheckMagic(stream);
         verifyZipHeader(checkedStream);
-        
+
+        final InputStream processStream = closeStream ? checkedStream : new 
NoCloseInputStream(checkedStream);
         // Open as a proper zip stream
-        return new ZipArchiveThresholdInputStream(new 
ZipArchiveInputStream(checkedStream));
+        return new ZipArchiveThresholdInputStream(new 
ZipArchiveInputStream(processStream));
     }
 
     /**

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java?rev=1913359&r1=1913358&r2=1913359&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
 Thu Oct 26 18:09:38 2023
@@ -277,17 +277,40 @@ public class XSSFWorkbook extends POIXML
      *       pkg.close(); // gracefully closes the underlying zip file
      *   }</pre>
      *
+     * @param stream The InputStream, which is closed when it is read.
      * @throws IOException If reading data from the stream fails
      * @throws POIXMLException a RuntimeException that can be caused by 
invalid OOXML data
      * @throws IllegalStateException a number of other runtime exceptions can 
be thrown, especially if there are problems with the
      * input format
      */
-    public XSSFWorkbook(InputStream is) throws IOException {
-        this(is, false);
+    public XSSFWorkbook(InputStream stream) throws IOException {
+        this(stream, true);
     }
 
-    private XSSFWorkbook(InputStream is, boolean closeStream) throws 
IOException {
-        this(PackageHelper.open(is, closeStream));
+    /**
+     * Constructs a XSSFWorkbook object, by buffering the whole stream into 
memory
+     *  and then opening an {@link OPCPackage} object for it.
+     *
+     * <p>Using an {@link InputStream} requires more memory than using a File, 
so
+     *  if a {@link File} is available then you should instead do something 
like
+     *   <pre>{@code
+     *       OPCPackage pkg = OPCPackage.open(path);
+     *       XSSFWorkbook wb = new XSSFWorkbook(pkg);
+     *       // work with the wb object
+     *       ......
+     *       pkg.close(); // gracefully closes the underlying zip file
+     *   }</pre>
+     *
+     * @param stream The InputStream.
+     * @param closeStream Whether to close the stream.
+     * @throws IOException If reading data from the stream fails
+     * @throws POIXMLException a RuntimeException that can be caused by 
invalid OOXML data
+     * @throws IllegalStateException a number of other runtime exceptions can 
be thrown, especially if there are problems with the
+     * input format
+     * @since POI 5.2.5
+     */
+    public XSSFWorkbook(InputStream stream, boolean closeStream) throws 
IOException {
+        this(PackageHelper.open(stream, closeStream));
     }
 
     /**

Modified: 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java?rev=1913359&r1=1913358&r2=1913359&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java
 Thu Oct 26 18:09:38 2023
@@ -1460,13 +1460,17 @@ public final class TestXSSFWorkbook exte
         }
     }
 
-    static class NoCloseInputStream extends FilterInputStream {
-        NoCloseInputStream(InputStream stream) {
-            super(stream);
+    @Test
+    void testWorkbookCloseCanBeStoppedFromClosingInputStream() throws 
Exception {
+        try (WrappedStream stream = new WrappedStream(
+                HSSFTestDataSamples.openSampleFileStream("github-321.xlsx"))) {
+            // uses new constructor, available since POI 5.2.5
+            try (XSSFWorkbook wb = new XSSFWorkbook(stream, false)) {
+                XSSFSheet xssfSheet = wb.getSheetAt(0);
+                assertNotNull(xssfSheet);
+            }
+            assertFalse(stream.isClosed(), "stream should not be closed by 
XSSFWorkbook");
         }
-
-        @Override
-        public void close() {}
     }
 
     @Test
@@ -1494,9 +1498,8 @@ public final class TestXSSFWorkbook exte
             try (ZipArchiveInputStream zis = new 
ZipArchiveInputStream(Files.newInputStream(tempFile.toPath()))) {
                 ZipArchiveEntry entry;
                 while ((entry = zis.getNextZipEntry()) != null) {
-                    // NoCloseInputStream is needed to stop XSSFWorkbook 
closing the underlying InputStream
-                    // this might not sound great but POI has worked like this 
for years and we can't just change it
-                    XSSFWorkbook wb = new XSSFWorkbook(new 
NoCloseInputStream(zis));
+                    // Since POI 5.2.5, you can stop XSSFWorkbook closing the 
InputStream by using this new constructor
+                    XSSFWorkbook wb = new XSSFWorkbook(zis, false);
                     assertNotNull(wb);
                     count++;
                 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to