Author: kiwiwings
Date: Wed Apr 25 10:03:39 2018
New Revision: 1830061

URL: http://svn.apache.org/viewvc?rev=1830061&view=rev
Log:
Bug 62187 - commit Commons Compress unrelated changes

Added:
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java 
  (with props)
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
   (with props)
Removed:
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/CompressionOption.java
    
poi/trunk/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestZipPackage.java
Modified:
    
poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java
    poi/trunk/src/java/org/apache/poi/UnsupportedFileFormatException.java
    poi/trunk/src/ooxml/java/org/apache/poi/POIXMLFactory.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/exceptions/NotOfficeXmlFileException.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipFileZipEntrySource.java
    
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java
    
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java
    
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/dev/XSSFDump.java
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/openxml4j/opc/TestPackage.java
    
poi/trunk/src/ooxml/testcases/org/apache/poi/openxml4j/opc/ZipFileAssert.java
    
poi/trunk/src/ooxml/testcases/org/apache/poi/openxml4j/opc/internal/marshallers/TestZipPackagePropertiesMarshaller.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java
    
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbook.java

Modified: 
poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java
 (original)
+++ 
poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java
 Wed Apr 25 10:03:39 2018
@@ -74,12 +74,11 @@ import org.apache.poi.xssf.usermodel.XSS
  * </p>
  * See <a "http://poi.apache.org/spreadsheet/how-to.html#sxssf";>
  *     http://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.
-
- *
- * @author Yegor Kozlov
  */
-public class BigGridDemo {
+public final class BigGridDemo {
     private static final String XML_ENCODING = "UTF-8";
+
+    private BigGridDemo() {}
     
     public static void main(String[] args) throws Exception {
 
@@ -229,17 +228,17 @@ public class BigGridDemo {
         private final Writer _out;
         private int _rownum;
 
-        public SpreadsheetWriter(Writer out){
+        SpreadsheetWriter(Writer out){
             _out = out;
         }
 
-        public void beginSheet() throws IOException {
+        void beginSheet() throws IOException {
             _out.write("<?xml version=\"1.0\" encoding=\""+XML_ENCODING+"\"?>" 
+
                     "<worksheet 
xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\";>" );
             _out.write("<sheetData>\n");
         }
 
-        public void endSheet() throws IOException {
+        void endSheet() throws IOException {
             _out.write("</sheetData>");
             _out.write("</worksheet>");
         }
@@ -249,7 +248,7 @@ public class BigGridDemo {
          *
          * @param rownum 0-based row number
          */
-        public void insertRow(int rownum) throws IOException {
+        void insertRow(int rownum) throws IOException {
             _out.write("<row r=\""+(rownum+1)+"\">\n");
             this._rownum = rownum;
         }
@@ -257,7 +256,7 @@ public class BigGridDemo {
         /**
          * Insert row end marker
          */
-        public void endRow() throws IOException {
+        void endRow() throws IOException {
             _out.write("</row>\n");
         }
 

Modified: poi/trunk/src/java/org/apache/poi/UnsupportedFileFormatException.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/UnsupportedFileFormatException.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/UnsupportedFileFormatException.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/UnsupportedFileFormatException.java Wed 
Apr 25 10:03:39 2018
@@ -23,7 +23,11 @@ package org.apache.poi;
 public abstract class UnsupportedFileFormatException extends 
IllegalArgumentException {
     private static final long serialVersionUID = -8281969197282030046L;
 
-    public UnsupportedFileFormatException(String s) {
+    protected UnsupportedFileFormatException(String s) {
                super(s);
        }
+
+    protected UnsupportedFileFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
\ No newline at end of file

Modified: poi/trunk/src/ooxml/java/org/apache/poi/POIXMLFactory.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/POIXMLFactory.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/POIXMLFactory.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/POIXMLFactory.java Wed Apr 25 
10:03:39 2018
@@ -60,7 +60,7 @@ public abstract class POIXMLFactory {
                 return createDocumentPart(cls, ORPHAN_PART, new 
Object[]{part});
             }
         } catch (Exception e) {
-            throw new POIXMLException(e);
+            throw new POIXMLException((e.getCause() != null ? e.getCause() : 
e).getMessage(), e);
         }
     }
     

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/exceptions/NotOfficeXmlFileException.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/exceptions/NotOfficeXmlFileException.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/exceptions/NotOfficeXmlFileException.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/exceptions/NotOfficeXmlFileException.java
 Wed Apr 25 10:03:39 2018
@@ -26,4 +26,8 @@ public class NotOfficeXmlFileException e
     public NotOfficeXmlFileException(String message) {
         super(message);
     }
+
+    public NotOfficeXmlFileException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java Wed 
Apr 25 10:03:39 2018
@@ -76,12 +76,12 @@ public abstract class OPCPackage impleme
        /**
         * Package access.
         */
-       private PackageAccess packageAccess;
+       private final PackageAccess packageAccess;
 
        /**
         * Package parts collection.
         */
-       protected PackagePartCollection partList;
+       private PackagePartCollection partList;
 
        /**
         * Package relationships.
@@ -91,17 +91,17 @@ public abstract class OPCPackage impleme
        /**
         * Part marshallers by content type.
         */
-       protected Map<ContentType, PartMarshaller> partMarshallers;
+       protected final Map<ContentType, PartMarshaller> partMarshallers = new 
HashMap<>(5);
 
        /**
         * Default part marshaller.
         */
-       protected PartMarshaller defaultPartMarshaller;
+       protected final PartMarshaller defaultPartMarshaller = new 
DefaultMarshaller();
 
        /**
         * Part unmarshallers by content type.
         */
-       protected Map<ContentType, PartUnmarshaller> partUnmarshallers;
+       protected final Map<ContentType, PartUnmarshaller> partUnmarshallers = 
new HashMap<>(2);
 
        /**
         * Core package properties.
@@ -138,41 +138,27 @@ public abstract class OPCPackage impleme
                if (getClass() != ZipPackage.class) {
                        throw new IllegalArgumentException("PackageBase may not 
be subclassed");
                }
-               init();
                this.packageAccess = access;
-       }
 
-       /**
-        * Initialize the package instance.
-        */
-       private void init() {
-               this.partMarshallers = new HashMap<>(5);
-               this.partUnmarshallers = new HashMap<>(2);
+               final ContentType contentType = newCorePropertiesPart();
+               // TODO Delocalize specialized marshallers
+               this.partUnmarshallers.put(contentType, new 
PackagePropertiesUnmarshaller());
+               this.partMarshallers.put(contentType, new 
ZipPackagePropertiesMarshaller());
+       }
 
+       private static ContentType newCorePropertiesPart() {
                try {
-                       // Add 'default' unmarshaller
-                       this.partUnmarshallers.put(new ContentType(
-                                       ContentTypes.CORE_PROPERTIES_PART),
-                                       new PackagePropertiesUnmarshaller());
-
-                       // Add default marshaller
-                       this.defaultPartMarshaller = new DefaultMarshaller();
-                       // TODO Delocalize specialized marshallers
-                       this.partMarshallers.put(new ContentType(
-                                       ContentTypes.CORE_PROPERTIES_PART),
-                                       new ZipPackagePropertiesMarshaller());
+                       return new 
ContentType(ContentTypes.CORE_PROPERTIES_PART);
                } catch (InvalidFormatException e) {
                        // Should never happen
                        throw new OpenXML4JRuntimeException(
-                                       "Package.init() : this exception should 
never happen, " +
-                                       "if you read this message please send a 
mail to the developers team. : " +
-                                       e.getMessage(),
-                                       e
+                               "Package.init() : this exception should never 
happen, " +
+                               "if you read this message please send a mail to 
the developers team. : " +
+                               e.getMessage(), e
                        );
                }
        }
 
-
        /**
         * Open a package with read/write permission.
         *
@@ -625,7 +611,8 @@ public abstract class OPCPackage impleme
                                return null;
                        }
                }
-               return getPartImpl(partName);
+
+               return partList.get(partName);
        }
 
        /**
@@ -737,25 +724,16 @@ public abstract class OPCPackage impleme
 
                        // Check rule M4.1 -> A format consumer shall consider 
more than
                        // one core properties relationship for a package to be 
an error
-                  // (We just log it and move on, as real files break this!)
+                   // (We just log it and move on, as real files break this!)
                        boolean hasCorePropertiesPart = false;
                        boolean needCorePropertiesPart = true;
 
-                       PackagePart[] parts = this.getPartsImpl();
-                       this.partList = new PackagePartCollection();
-                       for (PackagePart part : parts) {
-                               if (partList.containsKey(part._partName)) {
-                                       throw new InvalidFormatException(
-                                                       "A part with the name 
'" +
-                                                       part._partName +
-                                                       "' already exist : 
Packages shall not contain equivalent " +
-                                                       "part names and package 
implementers shall neither create " +
-                                                       "nor recognize packages 
with equivalent part names. [M1.12]");
-                               }
+                       partList = getPartsImpl();
+                       for (PackagePart part : new 
ArrayList<>(partList.sortedValues())) {
+                           part.loadRelationships();
 
                                // Check OPC compliance rule M4.1
-                               if (part.getContentType().equals(
-                                               
ContentTypes.CORE_PROPERTIES_PART)) {
+                               if 
(ContentTypes.CORE_PROPERTIES_PART.equals(part.getContentType())) {
                                        if (!hasCorePropertiesPart) {
                                                hasCorePropertiesPart = true;
                                        } else {
@@ -768,11 +746,10 @@ public abstract class OPCPackage impleme
                                PartUnmarshaller partUnmarshaller = 
partUnmarshallers.get(part._contentType);
 
                                if (partUnmarshaller != null) {
-                                       UnmarshallContext context = new 
UnmarshallContext(this,
-                                                       part._partName);
+                                       UnmarshallContext context = new 
UnmarshallContext(this, part._partName);
                                        try {
-                                               PackagePart unmarshallPart = 
partUnmarshaller
-                                                               
.unmarshall(context, part.getInputStream());
+                                               PackagePart unmarshallPart = 
partUnmarshaller.unmarshall(context, part.getInputStream());
+                                               
partList.remove(part.getPartName());
                                                
partList.put(unmarshallPart._partName, unmarshallPart);
 
                                                // Core properties case-- use 
first CoreProperties part we come across
@@ -790,12 +767,6 @@ public abstract class OPCPackage impleme
                                        } catch (InvalidOperationException 
invoe) {
                                                throw new 
InvalidFormatException(invoe.getMessage(), invoe);
                                        }
-                               } else {
-                                       try {
-                                               partList.put(part._partName, 
part);
-                                       } catch (InvalidOperationException e) {
-                                               throw new 
InvalidFormatException(e.getMessage(), e);
-                                       }
                                }
                        }
                }
@@ -1457,6 +1428,7 @@ public abstract class OPCPackage impleme
         }
        }
 
+
        /* Accesseurs */
 
        /**
@@ -1576,20 +1548,11 @@ public abstract class OPCPackage impleme
                        throws IOException;
 
        /**
-        * Get the package part mapped to the specified URI.
-        *
-        * @param partName
-        *            The URI of the part to retrieve.
-        * @return The package part located by the specified URI, else 
<b>null</b>.
-        */
-       protected abstract PackagePart getPartImpl(PackagePartName partName);
-
-       /**
         * Get all parts link to the package.
         *
         * @return A list of the part owned by the package.
         */
-       protected abstract PackagePart[] getPartsImpl()
+       protected abstract PackagePartCollection getPartsImpl()
                        throws InvalidFormatException;
 
     /**

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePart.java Wed 
Apr 25 10:03:39 2018
@@ -106,8 +106,9 @@ public abstract class PackagePart implem
                _isRelationshipPart = this._partName.isRelationshipPartURI();
 
                // Load relationships if any
-               if (loadRelationships)
+               if (loadRelationships) {
                        loadRelationships();
+               }
        }
 
        /**
@@ -558,7 +559,7 @@ public abstract class PackagePart implem
         * @throws InvalidFormatException
         *             Throws if
         */
-       private void loadRelationships() throws InvalidFormatException {
+       /* package */ void loadRelationships() throws InvalidFormatException {
                if (this._relationships == null && !this._isRelationshipPart) {
                        this.throwExceptionIfRelationship();
                        _relationships = new 
PackageRelationshipCollection(this);

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java
 Wed Apr 25 10:03:39 2018
@@ -45,12 +45,12 @@ public final class PackageRelationshipCo
     /**
      * Package relationships ordered by ID.
      */
-    private TreeMap<String, PackageRelationship> relationshipsByID;
+    private final TreeMap<String, PackageRelationship> relationshipsByID = new 
TreeMap<>();
 
     /**
      * Package relationships ordered by type.
      */
-    private TreeMap<String, PackageRelationship> relationshipsByType;
+    private final TreeMap<String, PackageRelationship> relationshipsByType = 
new TreeMap<>();
 
     /**
      * A lookup of internal relationships to avoid
@@ -88,8 +88,6 @@ public final class PackageRelationshipCo
      * Constructor.
      */
     PackageRelationshipCollection() {
-        relationshipsByID = new TreeMap<>();
-        relationshipsByType = new TreeMap<>();
     }
 
     /**
@@ -149,8 +147,6 @@ public final class PackageRelationshipCo
      */
     public PackageRelationshipCollection(OPCPackage container, PackagePart 
part)
             throws InvalidFormatException {
-        this();
-
         if (container == null)
             throw new IllegalArgumentException("container needs to be 
specified");
 

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java Wed 
Apr 25 10:03:39 2018
@@ -17,17 +17,23 @@
 
 package org.apache.poi.openxml4j.opc;
 
+import static org.apache.poi.openxml4j.opc.ContentTypes.RELATIONSHIPS_PART;
+import static 
org.apache.poi.openxml4j.opc.internal.ContentTypeManager.CONTENT_TYPES_PART_NAME;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.Enumeration;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
+import org.apache.poi.UnsupportedFileFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
 import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
@@ -41,10 +47,10 @@ import org.apache.poi.openxml4j.opc.inte
 import org.apache.poi.openxml4j.opc.internal.ZipContentTypeManager;
 import org.apache.poi.openxml4j.opc.internal.ZipHelper;
 import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
+import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream;
 import org.apache.poi.openxml4j.util.ZipEntrySource;
 import org.apache.poi.openxml4j.util.ZipFileZipEntrySource;
 import org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource;
-import org.apache.poi.openxml4j.util.ZipSecureFile.ThresholdInputStream;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
@@ -95,12 +101,12 @@ public final class ZipPackage extends OP
      */
     ZipPackage(InputStream in, PackageAccess access) throws IOException {
         super(access);
-        ThresholdInputStream zis = ZipHelper.openZipStream(in);
+        ZipArchiveThresholdInputStream zis = ZipHelper.openZipStream(in);
         try {
             this.zipArchive = new ZipInputStreamZipEntrySource(zis);
         } catch (final IOException e) {
             IOUtils.closeQuietly(zis);
-            throw new IOException("Failed to read zip entry source", e);
+            throw e;
         }
     }
 
@@ -138,6 +144,9 @@ public final class ZipPackage extends OP
             if (access == PackageAccess.WRITE) {
                 throw new InvalidOperationException("Can't open the specified 
file: '" + file + "'", e);
             }
+            if ("java.util.zip.ZipException: archive is not a ZIP 
archive".equals(e.getMessage())) {
+                throw new NotOfficeXmlFileException("archive is not a ZIP 
archive", e);
+            }
             LOG.log(POILogger.ERROR, "Error in zip file "+file+" - falling 
back to stream processing (i.e. ignoring zip central directory)");
             ze = openZipEntrySourceStream(file);
         }
@@ -159,19 +168,19 @@ public final class ZipPackage extends OP
         try {
             // read from the file input stream
             return openZipEntrySourceStream(fis);
+        } catch (final 
InvalidOperationException|UnsupportedFileFormatException e) {
+            // abort: close the zip input stream
+            IOUtils.closeQuietly(fis);
+            throw e;
         } catch (final Exception e) {
             // abort: close the file input stream
             IOUtils.closeQuietly(fis);
-            if (e instanceof InvalidOperationException) {
-                throw (InvalidOperationException)e;
-            } else {
-                throw new InvalidOperationException("Failed to read the file 
input stream from file: '" + file + "'", e);
-            }
+            throw new InvalidOperationException("Failed to read the file input 
stream from file: '" + file + "'", e);
         }
     }
     
     private static ZipEntrySource openZipEntrySourceStream(FileInputStream 
fis) throws InvalidOperationException {
-        final ThresholdInputStream zis;
+        final ZipArchiveThresholdInputStream zis;
         // Acquire a resource that is needed to read the next level of 
openZipEntrySourceStream
         try {
             // open the zip input stream
@@ -185,18 +194,18 @@ public final class ZipPackage extends OP
         try {
             // read from the zip input stream
             return openZipEntrySourceStream(zis);
+        } catch (final 
InvalidOperationException|UnsupportedFileFormatException e) {
+            // abort: close the zip input stream
+            IOUtils.closeQuietly(zis);
+            throw e;
         } catch (final Exception e) {
             // abort: close the zip input stream
             IOUtils.closeQuietly(zis);
-            if (e instanceof InvalidOperationException) {
-                throw (InvalidOperationException)e;
-            } else {
-                throw new InvalidOperationException("Failed to read the zip 
entry source stream", e);
-            }
+            throw new InvalidOperationException("Failed to read the zip entry 
source stream", e);
         }
     }
     
-    private static ZipEntrySource 
openZipEntrySourceStream(ThresholdInputStream zis) throws 
InvalidOperationException {
+    private static ZipEntrySource 
openZipEntrySourceStream(ZipArchiveThresholdInputStream zis) throws 
InvalidOperationException {
         // Acquire the final level resource. If this is acquired successfully, 
the zip package was read successfully from the input stream
         try {
             // open the zip entry source stream
@@ -224,149 +233,115 @@ public final class ZipPackage extends OP
     /**
      * Retrieves the parts from this package. We assume that the package has 
not
      * been yet inspect to retrieve all the parts, this method will open the
-     * archive and look for all parts contain inside it. If the package part
-     * list is not empty, it will be emptied.
+     * archive and look for all parts contain inside it.
      *
      * @return All parts contain in this package.
      * @throws InvalidFormatException if the package is not valid.
      */
     @Override
-    protected PackagePart[] getPartsImpl() throws InvalidFormatException {
-        if (this.partList == null) {
-            // The package has just been created, we create an empty part
-            // list.
-            this.partList = new PackagePartCollection();
-        }
+    protected PackagePartCollection getPartsImpl() throws 
InvalidFormatException {
+        final PackagePartCollection newPartList = new PackagePartCollection();
 
-        if (this.zipArchive == null) {
-            return this.partList.sortedValues().toArray(
-                    new PackagePart[this.partList.size()]);
+        if (zipArchive == null) {
+            return newPartList;
         }
 
         // First we need to parse the content type part
-        Enumeration<? extends ZipEntry> entries = this.zipArchive.getEntries();
-        while (entries.hasMoreElements()) {
-            ZipEntry entry = entries.nextElement();
-            if (entry.getName().equalsIgnoreCase(
-                    ContentTypeManager.CONTENT_TYPES_PART_NAME)) {
-                try {
-                    this.contentTypeManager = new ZipContentTypeManager(
-                            getZipArchive().getInputStream(entry), this);
-                } catch (IOException e) {
-                    throw new InvalidFormatException(e.getMessage(), e);
-                }
-                break;
+        final ZipEntry contentTypeEntry =
+                zipArchive.getEntry(CONTENT_TYPES_PART_NAME);
+        if (contentTypeEntry != null) {
+            try {
+                this.contentTypeManager = new ZipContentTypeManager(
+                        zipArchive.getInputStream(contentTypeEntry), this);
+            } catch (IOException e) {
+                throw new InvalidFormatException(e.getMessage(), e);
             }
-        }
-
-        // At this point, we should have loaded the content type part
-        if (this.contentTypeManager == null) {
+        } else {
             // Is it a different Zip-based format?
-            int numEntries = 0;
-            boolean hasMimetype = false;
-            boolean hasSettingsXML = false;
-            entries = this.zipArchive.getEntries();
-            while (entries.hasMoreElements()) {
-                final ZipEntry entry = entries.nextElement();
-                final String name = entry.getName();
-                if (MIMETYPE.equals(name)) {
-                    hasMimetype = true;
-                }
-                if (SETTINGS_XML.equals(name)) {
-                    hasSettingsXML = true;
-                }
-                numEntries++;
-            }
+            final boolean hasMimetype = zipArchive.getEntry(MIMETYPE) != null;
+            final boolean hasSettingsXML = zipArchive.getEntry(SETTINGS_XML) 
!= null;
             if (hasMimetype && hasSettingsXML) {
                 throw new ODFNotOfficeXmlFileException(
-                   "The supplied data appears to be in ODF (Open Document) 
Format. " +
-                   "Formats like these (eg ODS, ODP) are not supported, try 
Apache ODFToolkit");
+                        "The supplied data appears to be in ODF (Open 
Document) Format. " +
+                                "Formats like these (eg ODS, ODP) are not 
supported, try Apache ODFToolkit");
             }
-            if (numEntries == 0) {
+            if (!zipArchive.getEntries().hasMoreElements()) {
                 throw new NotOfficeXmlFileException(
-                   "No valid entries or contents found, this is not a valid 
OOXML " +
-                   "(Office Open XML) file");
+                        "No valid entries or contents found, this is not a 
valid OOXML " +
+                                "(Office Open XML) file");
             }
-
             // Fallback exception
             throw new InvalidFormatException(
-                "Package should contain a content type part [M1.13]");
+                    "Package should contain a content type part [M1.13]");
         }
 
         // Now create all the relationships
         // (Need to create relationships before other
         //  parts, otherwise we might create a part before
         //  its relationship exists, and then it won't tie up)
-        entries = this.zipArchive.getEntries();
-        while (entries.hasMoreElements()) {
-            ZipEntry entry = entries.nextElement();
-            PackagePartName partName = buildPartName(entry);
-            if(partName == null) {
-                continue;
-            }
+        final List<EntryTriple> entries =
+                Collections.list(zipArchive.getEntries()).stream()
+                        .map(zae -> new EntryTriple(zae, contentTypeManager))
+                        .filter(mm -> mm.partName != null)
+                        .sorted()
+                        .collect(Collectors.toList());
 
-            // Only proceed for Relationships at this stage
-            String contentType = contentTypeManager.getContentType(partName);
-            if (contentType != null && 
contentType.equals(ContentTypes.RELATIONSHIPS_PART)) {
-                try {
-                    PackagePart part = new ZipPackagePart(this, entry, 
partName, contentType);
-                    partList.put(partName, part);
-                } catch (InvalidOperationException e) {
-                    throw new InvalidFormatException(e.getMessage(), e);
-                }
-            }
+        for (final EntryTriple et : entries) {
+            et.register(newPartList);
         }
 
-        // Then we can go through all the other parts
-        entries = this.zipArchive.getEntries();
-        while (entries.hasMoreElements()) {
-            ZipEntry entry = entries.nextElement();
-            PackagePartName partName = buildPartName(entry);
-            if(partName == null) {
-                continue;
+        return newPartList;
+    }
+
+    private class EntryTriple implements Comparable<EntryTriple> {
+        final ZipEntry zipArchiveEntry;
+        final PackagePartName partName;
+        final String contentType;
+
+        EntryTriple(final ZipEntry zipArchiveEntry, final ContentTypeManager 
contentTypeManager) {
+            this.zipArchiveEntry = zipArchiveEntry;
+
+            final String entryName = zipArchiveEntry.getName();
+            PackagePartName ppn = null;
+            try {
+                // We get an error when we parse [Content_Types].xml
+                // because it's not a valid URI.
+                ppn = (CONTENT_TYPES_PART_NAME.equalsIgnoreCase(entryName)) ? 
null
+                    : 
PackagingURIHelper.createPartName(ZipHelper.getOPCNameFromZipItemName(entryName));
+            } catch (Exception e) {
+                // We assume we can continue, even in degraded mode ...
+                LOG.log(POILogger.WARN,"Entry " + entryName + " is not valid, 
so this part won't be add to the package.", e);
             }
 
-            String contentType = contentTypeManager.getContentType(partName);
-            if (contentType != null && 
contentType.equals(ContentTypes.RELATIONSHIPS_PART)) {
-                // Already handled
+            this.partName = ppn;
+            this.contentType = (ppn == null) ? null : 
contentTypeManager.getContentType(partName);
+        }
+
+        void register(final PackagePartCollection partList) throws 
InvalidFormatException {
+            if (contentType == null) {
+                throw new InvalidFormatException("The part " + 
partName.getURI().getPath() + " does not have any " +
+                        "content type ! Rule: Package require content types 
when retrieving a part from a package. [M.1.14]");
             }
-            else if (contentType != null) {
-                try {
-                    PackagePart part = new ZipPackagePart(this, entry, 
partName, contentType);
-                    partList.put(partName, part);
-                } catch (InvalidOperationException e) {
-                    throw new InvalidFormatException(e.getMessage(), e);
-                }
-            } else {
+
+            if (partList.containsKey(partName)) {
                 throw new InvalidFormatException(
-                    "The part " + partName.getURI().getPath()
-                    + " does not have any content type ! Rule: Package require 
content types when retrieving a part from a package. [M.1.14]");
+                    "A part with the name '"+partName+"' already exist : 
Packages shall not contain equivalent part names " +
+                    "and package implementers shall neither create nor 
recognize packages with equivalent part names. [M1.12]");
             }
-        }
-
-        return partList.sortedValues().toArray(new 
PackagePart[partList.size()]);
-    }
 
-    /**
-     * Builds a PackagePartName for the given ZipEntry,
-     *  or null if it's the content types / invalid part
-     */
-    private PackagePartName buildPartName(ZipEntry entry) {
-        try {
-            // We get an error when we parse [Content_Types].xml
-            // because it's not a valid URI.
-            if (entry.getName().equalsIgnoreCase(
-                    ContentTypeManager.CONTENT_TYPES_PART_NAME)) {
-                return null;
+            try {
+                partList.put(partName, new ZipPackagePart(ZipPackage.this, 
zipArchiveEntry, partName, contentType, false));
+            } catch (InvalidOperationException e) {
+                throw new InvalidFormatException(e.getMessage(), e);
             }
-            return PackagingURIHelper.createPartName(ZipHelper
-                    .getOPCNameFromZipItemName(entry.getName()));
-        } catch (Exception e) {
-            // We assume we can continue, even in degraded mode ...
-            LOG.log(POILogger.WARN,"Entry "
-                                      + entry.getName()
-                                      + " is not valid, so this part won't be 
add to the package.", e);
-            return null;
+        }
+
+        @Override
+        public int compareTo(EntryTriple o) {
+            final int contentTypeOrder1 = 
RELATIONSHIPS_PART.equals(contentType) ? -1 : 1;
+            final int contentTypeOrder2 = 
RELATIONSHIPS_PART.equals(o.contentType) ? -1 : 1;
+            final int cmpCT = Integer.compare(contentTypeOrder1, 
contentTypeOrder2);
+            return cmpCT != 0 ? cmpCT : partName.compareTo(o.partName);
         }
     }
 
@@ -494,21 +469,6 @@ public final class ZipPackage extends OP
                }
        }
 
-    /**
-     * Implement the getPart() method to retrieve a part from its URI in the
-     * current package
-     *
-     *
-     * @see #getPart(PackageRelationship)
-     */
-    @Override
-    protected PackagePart getPartImpl(PackagePartName partName) {
-        if (partList.containsKey(partName)) {
-            return partList.get(partName);
-        }
-        return null;
-    }
-
        /**
         * Save this package into the specified stream
         *
@@ -523,13 +483,8 @@ public final class ZipPackage extends OP
                // Check that the document was open in write mode
                throwExceptionIfReadOnly();
 
-               final ZipOutputStream zos;
-               try {
-                       if (!(outputStream instanceof ZipOutputStream)) {
-                zos = new ZipOutputStream(outputStream);
-            } else {
-                zos = (ZipOutputStream) outputStream;
-            }
+               try (final ZipOutputStream zos = (outputStream instanceof 
ZipOutputStream)
+                ? (ZipOutputStream) outputStream : new 
ZipOutputStream(outputStream)) {
 
                        // If the core properties part does not exist in the 
part list,
                        // we save it as well
@@ -574,20 +529,14 @@ public final class ZipPackage extends OP
 
                                final PackagePartName ppn = part.getPartName();
                                LOG.log(POILogger.DEBUG,"Save part '" + 
ZipHelper.getZipItemNameFromOPCName(ppn.getName()) + "'");
-                               PartMarshaller marshaller = 
partMarshallers.get(part._contentType);
-                               String errMsg = "The part " + ppn.getURI() + " 
failed to be saved in the stream with marshaller ";
+                               final PartMarshaller marshaller = 
partMarshallers.get(part._contentType);
 
-                               if (marshaller != null) {
-                                       if (!marshaller.marshall(part, zos)) {
-                                               throw new 
OpenXML4JException(errMsg + marshaller);
-                                       }
-                               } else {
-                                       if 
(!defaultPartMarshaller.marshall(part, zos)) {
-                        throw new OpenXML4JException(errMsg + 
defaultPartMarshaller);
-                    }
-                               }
+                               final PartMarshaller pm = (marshaller != null) 
? marshaller : defaultPartMarshaller;
+                if (!pm.marshall(part, zos)) {
+                    String errMsg = "The part " + ppn.getURI() + " failed to 
be saved in the stream with marshaller ";
+                    throw new OpenXML4JException(errMsg + pm);
+                }
                        }
-                       zos.close();
                } catch (OpenXML4JRuntimeException e) {
                        // no need to wrap this type of Exception
                        throw e;

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java 
Wed Apr 25 10:03:39 2018
@@ -25,6 +25,7 @@ import java.util.zip.ZipEntry;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.internal.ContentType;
 import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
 import org.apache.poi.util.NotImplemented;
 
@@ -48,11 +49,11 @@ public class ZipPackagePart extends Pack
         * @param container
         *            The container package.
         * @param partName
-        *            Part name.
+        *            The part name.
         * @param contentType
         *            Content type.
         * @throws InvalidFormatException
-        *             Throws if the content of this part invalid.
+        *             Throws if the content of this part is invalid.
         */
        public ZipPackagePart(OPCPackage container, PackagePartName partName,
                        String contentType) throws InvalidFormatException {
@@ -73,10 +74,10 @@ public class ZipPackagePart extends Pack
         * @throws InvalidFormatException
         *             Throws if the content of this part is invalid.
         */
-       public ZipPackagePart(OPCPackage container, ZipEntry zipEntry,
-                       PackagePartName partName, String contentType)
+       /* package */ ZipPackagePart(OPCPackage container, ZipEntry zipEntry,
+                                                 PackagePartName partName, 
String contentType, boolean loadRelationships)
                        throws InvalidFormatException {
-               super(container, partName, contentType);
+               super(container, partName, new ContentType(contentType), 
loadRelationships);
                this.zipEntry = zipEntry;
        }
 

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
 Wed Apr 25 10:03:39 2018
@@ -57,26 +57,23 @@ public class ZipContentTypeManager exten
        @SuppressWarnings("resource")
     @Override
        public boolean saveImpl(Document content, OutputStream out) {
-               ZipOutputStream zos = null;
-               if (out instanceof ZipOutputStream)
-                       zos = (ZipOutputStream) out;
-               else
-                       zos = new ZipOutputStream(out);
+               final ZipOutputStream zos = (out instanceof ZipOutputStream)
+                               ? (ZipOutputStream) out : new 
ZipOutputStream(out);
 
                ZipEntry partEntry = new ZipEntry(CONTENT_TYPES_PART_NAME);
                try {
                        // Referenced in ZIP
                        zos.putNextEntry(partEntry);
-                       // Saving data in the ZIP file
-                       if (!StreamHelper.saveXmlInStream(content, zos)) {
-                           return false;
+                       try {
+                               // Saving data in the ZIP file
+                               return StreamHelper.saveXmlInStream(content, 
zos);
+                       } finally {
+                               zos.closeEntry();
                        }
-                       zos.closeEntry();
                } catch (IOException ioe) {
                        logger.log(POILogger.ERROR, "Cannot write: " + 
CONTENT_TYPES_PART_NAME
                                        + " in Zip !", ioe);
                        return false;
                }
-               return true;
        }
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java 
(original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java 
Wed Apr 25 10:03:39 2018
@@ -24,9 +24,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.Enumeration;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 import java.util.zip.ZipInputStream;
 
 import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
@@ -34,8 +32,8 @@ import org.apache.poi.openxml4j.exceptio
 import org.apache.poi.openxml4j.opc.PackageRelationship;
 import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
 import org.apache.poi.openxml4j.opc.ZipPackage;
+import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream;
 import org.apache.poi.openxml4j.util.ZipSecureFile;
-import org.apache.poi.openxml4j.util.ZipSecureFile.ThresholdInputStream;
 import org.apache.poi.poifs.filesystem.FileMagic;
 import org.apache.poi.util.Internal;
 
@@ -73,24 +71,6 @@ public final class ZipHelper {
     }
 
     /**
-     * Retrieve the Zip entry of the content types part.
-     */
-    public static ZipEntry getContentTypeZipEntry(ZipPackage pkg) {
-        Enumeration<? extends ZipEntry> entries = 
pkg.getZipArchive().getEntries();
-
-        // Enumerate through the Zip entries until we find the one named
-        // '[Content_Types].xml'.
-        while (entries.hasMoreElements()) {
-            ZipEntry entry = entries.nextElement();
-            if (entry.getName().equals(
-                    ContentTypeManager.CONTENT_TYPES_PART_NAME)) {
-                return entry;
-            }
-        }
-        return null;
-    }
-
-    /**
      * Convert a zip name into an OPC name by adding a leading forward slash to
      * the specified item name.
      *
@@ -158,7 +138,7 @@ public final class ZipHelper {
      * Warning - this will consume the first few bytes of the stream,
      *  you should push-back or reset the stream after use!
      */
-    public static void verifyZipHeader(InputStream stream) throws 
NotOfficeXmlFileException, IOException {
+    private static void verifyZipHeader(InputStream stream) throws 
NotOfficeXmlFileException, IOException {
         InputStream is = FileMagic.prepareToCheckMagic(stream);
         FileMagic fm = FileMagic.valueOf(is);
 
@@ -191,14 +171,14 @@ public final class ZipHelper {
      * @return The zip stream freshly open.
      */
     @SuppressWarnings("resource")
-    public static ThresholdInputStream openZipStream(InputStream stream) 
throws IOException {
+    public static ZipArchiveThresholdInputStream openZipStream(InputStream 
stream) throws IOException {
         // Peek at the first few bytes to sanity check
         InputStream checkedStream = FileMagic.prepareToCheckMagic(stream);
         verifyZipHeader(checkedStream);
         
         // Open as a proper zip stream
         InputStream zis = new ZipInputStream(checkedStream);
-        return ZipSecureFile.addThreshold(zis);
+        return new ZipArchiveThresholdInputStream(zis);
     }
 
     /**
@@ -211,7 +191,7 @@ public final class ZipHelper {
      * @throws IOException if the zip file cannot be opened or closed to read 
the header signature
      * @throws NotOfficeXmlFileException if stream does not start with zip 
header signature
      */
-    public static ZipFile openZipFile(File file) throws IOException, 
NotOfficeXmlFileException {
+    public static ZipSecureFile openZipFile(File file) throws IOException, 
NotOfficeXmlFileException {
         if (!file.exists()) {
             throw new FileNotFoundException("File does not exist");
         }
@@ -235,7 +215,7 @@ public final class ZipHelper {
      *            The file path.
      * @return The zip archive freshly open.
      */
-    public static ZipFile openZipFile(String path) throws IOException {
+    public static ZipSecureFile openZipFile(String path) throws IOException {
         return openZipFile(new File(path));
     }
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java
 Wed Apr 25 10:03:39 2018
@@ -49,15 +49,15 @@ public final class ZipPackagePropertiesM
                try {
                        // Save in ZIP
                        zos.putNextEntry(ctEntry); // Add entry in ZIP
-                       super.marshall(part, out); // Marshall the properties 
inside a XML
-                       // Document
-                       if (!StreamHelper.saveXmlInStream(xmlDoc, out)) {
-                               return false;
+                       try {
+                               super.marshall(part, out); // Marshall the 
properties inside a XML
+                               // Document
+                               return StreamHelper.saveXmlInStream(xmlDoc, 
out);
+                       } finally {
+                               zos.closeEntry();
                        }
-                       zos.closeEntry();
                } catch (IOException e) {
                        throw new OpenXML4JException(e.getLocalizedMessage(), 
e);
                }
-               return true;
        }
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
 Wed Apr 25 10:03:39 2018
@@ -36,6 +36,7 @@ import org.apache.poi.openxml4j.opc.Targ
 import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
 import org.apache.poi.openxml4j.opc.internal.ZipHelper;
 import org.apache.poi.util.DocumentHelper;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.usermodel.XSSFRelation;
@@ -47,7 +48,6 @@ import org.w3c.dom.Element;
  */
 public final class ZipPartMarshaller implements PartMarshaller {
        private final static POILogger logger = 
POILogFactory.getLogger(ZipPartMarshaller.class);
-       private final static int READ_WRITE_FILE_BUFFER_SIZE = 8192;
 
        /**
         * Save the specified part.
@@ -80,17 +80,11 @@ public final class ZipPartMarshaller imp
                        zos.putNextEntry(partEntry);
 
                        // Saving data in the ZIP file
-                       InputStream ins = part.getInputStream();
-                       byte[] buff = new byte[READ_WRITE_FILE_BUFFER_SIZE];
-                       while (ins.available() > 0) {
-                               int resultRead = ins.read(buff);
-                               if (resultRead == -1) {
-                                       // End of file reached
-                                       break;
-                               }
-                               zos.write(buff, 0, resultRead);
+                       try (final InputStream ins = part.getInputStream()) {
+                               IOUtils.copy(ins, zos);
+                       } finally {
+                               zos.closeEntry();
                        }
-                       zos.closeEntry();
                } catch (IOException ioe) {
                        logger.log(POILogger.ERROR,"Cannot write: " + 
part.getPartName() + ": in ZIP",
                                        ioe);
@@ -178,14 +172,14 @@ public final class ZipPartMarshaller imp
                                
relPartName.getURI().toASCIIString()).getPath());
                try {
                        zos.putNextEntry(ctEntry);
-                       if (!StreamHelper.saveXmlInStream(xmlOutDoc, zos)) {
-                               return false;
+                       try {
+                               return StreamHelper.saveXmlInStream(xmlOutDoc, 
zos);
+                       } finally {
+                               zos.closeEntry();
                        }
-                       zos.closeEntry();
                } catch (IOException e) {
                        logger.log(POILogger.ERROR,"Cannot create zip entry " + 
relPartName, e);
                        return false;
                }
-               return true; // success
        }
 }

Added: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java?rev=1830061&view=auto
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java 
(added)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java 
Wed Apr 25 10:03:39 2018
@@ -0,0 +1,53 @@
+/* ====================================================================
+   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.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+
+import org.apache.poi.util.IOUtils;
+
+
+/**
+ * So we can close the real zip entry and still
+ *  effectively work with it.
+ * Holds the (decompressed!) data in memory, so
+ *  close this as soon as you can!
+ */
+/* package */ class ZipArchiveFakeEntry extends ZipEntry {
+    private final byte[] data;
+
+    ZipArchiveFakeEntry(ZipEntry entry, InputStream inp) throws IOException {
+        super(entry.getName());
+
+        final long entrySize = entry.getSize();
+
+        if (entrySize < -1 || entrySize>=Integer.MAX_VALUE) {
+            throw new IOException("ZIP entry size is too large or invalid");
+        }
+
+        // Grab the de-compressed contents for later
+        data = (entrySize == -1) ? IOUtils.toByteArray(inp) : 
IOUtils.toByteArray(inp, (int)entrySize);
+    }
+
+    public InputStream getInputStream() {
+        return new ByteArrayInputStream(data);
+    }
+}

Propchange: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java?rev=1830061&view=auto
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
 (added)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
 Wed Apr 25 10:03:39 2018
@@ -0,0 +1,243 @@
+/* ====================================================================
+   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.util;
+
+import static org.apache.poi.openxml4j.util.ZipSecureFile.MAX_ENTRY_SIZE;
+import static org.apache.poi.openxml4j.util.ZipSecureFile.MIN_INFLATE_RATIO;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.zip.InflaterInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.SuppressForbidden;
+
+public class ZipArchiveThresholdInputStream extends PushbackInputStream {
+    private static final POILogger LOG = 
POILogFactory.getLogger(ZipArchiveThresholdInputStream.class);
+
+    // don't alert for expanded sizes smaller than 100k
+    private static final long GRACE_ENTRY_SIZE = 100*1024L;
+
+    private static final String MAX_ENTRY_SIZE_MSG =
+        "Zip bomb detected! The file would exceed the max size of the expanded 
data in the zip-file.\n" +
+        "This may indicates that the file is used to inflate memory usage and 
thus could pose a security risk.\n" +
+        "You can adjust this limit via ZipSecureFile.setMaxEntrySize() if you 
need to work with files which are very large.\n" +
+        "Counter: %d, cis.counter: %d\n" +
+        "Limits: MAX_ENTRY_SIZE: %d, Entry: %s";
+
+    private static final String MIN_INFLATE_RATIO_MSG =
+        "Zip bomb detected! The file would exceed the max. ratio of compressed 
file size to the size of the expanded data.\n" +
+        "This may indicate that the file is used to inflate memory usage and 
thus could pose a security risk.\n" +
+        "You can adjust this limit via ZipSecureFile.setMinInflateRatio() if 
you need to work with files which exceed this limit.\n" +
+        "Counter: %d, cis.counter: %d, ratio: %f\n" +
+        "Limits: MIN_INFLATE_RATIO: %f, Entry: %s";
+
+    private static final String SECURITY_BLOCKED =
+        "SecurityManager doesn't allow manipulation via reflection for zipbomb 
detection - continue with original input stream";
+
+    /**
+     * the reference to the current entry is only used for a more detailed log 
message in case of an error
+     */
+    private ZipEntry entry;
+
+    private long counter;
+    private long markPos;
+    private final ZipArchiveThresholdInputStream cis;
+    private boolean guardState = true;
+
+
+    public ZipArchiveThresholdInputStream(final InputStream zipIS) throws 
IOException {
+        super(zipIS);
+        if (zipIS instanceof InflaterInputStream) {
+            cis = AccessController.doPrivileged(inject(zipIS));
+        } else {
+            // the inner stream is a ZipFileInputStream, i.e. the data wasn't 
compressed
+            cis = null;
+        }
+    }
+
+    private ZipArchiveThresholdInputStream(InputStream is, 
ZipArchiveThresholdInputStream cis) {
+        super(is);
+        this.cis = cis;
+    }
+
+    @SuppressForbidden
+    private static PrivilegedAction<ZipArchiveThresholdInputStream> 
inject(final InputStream zipIS) {
+        return () -> {
+            try {
+                final Field f = FilterInputStream.class.getDeclaredField("in");
+                f.setAccessible(true);
+                final InputStream oldInner = (InputStream)f.get(zipIS);
+                final ZipArchiveThresholdInputStream inner = new 
ZipArchiveThresholdInputStream(oldInner, null);
+                f.set(zipIS, inner);
+                return inner;
+            } catch (Exception ex) {
+                LOG.log(POILogger.WARN, SECURITY_BLOCKED, ex);
+            }
+            return null;
+        };
+    }
+
+    @Override
+    public int read() throws IOException {
+        int b = in.read();
+        if (b > -1) {
+            advance(1);
+        }
+        return b;
+    }
+
+    @Override
+    public int read(byte b[], int off, int len) throws IOException {
+        int cnt = in.read(b, off, len);
+        if (cnt > -1) {
+            advance(cnt);
+        }
+        return cnt;
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        long s = in.skip(n);
+        counter += s;
+        return s;
+    }
+
+    @Override
+    public synchronized void reset() throws IOException {
+        counter = markPos;
+        super.reset();
+    }
+
+    /**
+     * De-/activate threshold check.
+     * A disabled guard might make sense, when POI is processing its own 
temporary data (see #59743)
+     *
+     * @param guardState {@code true} (= default) enables the threshold check
+     */
+    public void setGuardState(boolean guardState) {
+        this.guardState = guardState;
+    }
+
+    public void advance(int advance) throws IOException {
+        counter += advance;
+
+        if (!guardState) {
+            return;
+        }
+
+        final String entryName = entry == null ? "not set" : entry.getName();
+        final long cisCount = (cis == null ? 0 : cis.counter);
+
+        // check the file size first, in case we are working on uncompressed 
streams
+        if(counter > MAX_ENTRY_SIZE) {
+            throw new IOException(String.format(Locale.ROOT, 
MAX_ENTRY_SIZE_MSG, counter, cisCount, MAX_ENTRY_SIZE, entryName));
+        }
+
+        // no expanded size?
+        if (cis == null) {
+            return;
+        }
+
+        // don't alert for small expanded size
+        if (counter <= GRACE_ENTRY_SIZE) {
+            return;
+        }
+
+        double ratio = (double)cis.counter/(double)counter;
+        if (ratio >= MIN_INFLATE_RATIO) {
+            return;
+        }
+
+        // one of the limits was reached, report it
+        throw new IOException(String.format(Locale.ROOT, 
MIN_INFLATE_RATIO_MSG, counter, cisCount, ratio, MIN_INFLATE_RATIO, entryName));
+    }
+
+    public ZipEntry getNextEntry() throws IOException {
+        if (!(in instanceof ZipInputStream)) {
+            throw new UnsupportedOperationException("underlying stream is not 
a ZipInputStream");
+        }
+        counter = 0;
+        return ((ZipInputStream)in).getNextEntry();
+    }
+
+    public void closeEntry() throws IOException {
+        if (!(in instanceof ZipInputStream)) {
+            throw new UnsupportedOperationException("underlying stream is not 
a ZipInputStream");
+        }
+        counter = 0;
+        ((ZipInputStream)in).closeEntry();
+    }
+
+    @Override
+    public void unread(int b) throws IOException {
+        if (!(in instanceof PushbackInputStream)) {
+            throw new UnsupportedOperationException("underlying stream is not 
a PushbackInputStream");
+        }
+        if (--counter < 0) {
+            counter = 0;
+        }
+        ((PushbackInputStream)in).unread(b);
+    }
+
+    @Override
+    public void unread(byte[] b, int off, int len) throws IOException {
+        if (!(in instanceof PushbackInputStream)) {
+            throw new UnsupportedOperationException("underlying stream is not 
a PushbackInputStream");
+        }
+        counter -= len;
+        if (--counter < 0) {
+            counter = 0;
+        }
+        ((PushbackInputStream)in).unread(b, off, len);
+    }
+
+    @Override
+    @SuppressForbidden("just delegating")
+    public int available() throws IOException {
+        return in.available();
+    }
+
+    @Override
+    public boolean markSupported() {
+        return in.markSupported();
+    }
+
+    @Override
+    public synchronized void mark(int readlimit) {
+        markPos = counter;
+        in.mark(readlimit);
+    }
+
+    /**
+     * Sets the zip entry for a detailed logging
+     * @param entry the entry
+     */
+    void setEntry(ZipEntry entry) {
+        this.entry = entry;
+    }
+}
\ No newline at end of file

Propchange: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipArchiveThresholdInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java 
Wed Apr 25 10:03:39 2018
@@ -33,23 +33,32 @@ public interface ZipEntrySource extends
        /**
         * Returns an Enumeration of all the Entries
         */
-       public Enumeration<? extends ZipEntry> getEntries();
-       
+       Enumeration<? extends ZipEntry> getEntries();
+
+       /**
+        * Return an entry by its path
+        * @param path the path in unix-notation
+        * @return the entry or {@code null} if not found
+        *
+        * @since POI 4.0.0
+        */
+       ZipEntry getEntry(String path);
+
        /**
         * Returns an InputStream of the decompressed 
         *  data that makes up the entry
         */
-       public InputStream getInputStream(ZipEntry entry) throws IOException;
+       InputStream getInputStream(ZipEntry entry) throws IOException;
        
        /**
         * Indicates we are done with reading, and 
         *  resources may be freed
         */
        @Override
-       public void close() throws IOException;
+       void close() throws IOException;
        
        /**
         * Has close been called already?
         */
-       public boolean isClosed();
+       boolean isClosed();
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipFileZipEntrySource.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipFileZipEntrySource.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipFileZipEntrySource.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipFileZipEntrySource.java
 Wed Apr 25 10:03:39 2018
@@ -16,6 +16,9 @@
 ==================================================================== */
 package org.apache.poi.openxml4j.util;
 
+import static org.apache.commons.collections4.IteratorUtils.asIterable;
+import static org.apache.commons.collections4.IteratorUtils.asIterator;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Enumeration;
@@ -33,16 +36,20 @@ public class ZipFileZipEntrySource imple
       this.zipArchive = zipFile;
    }
 
+   @Override
    public void close() throws IOException {
       if(zipArchive != null) {
          zipArchive.close();
       }
       zipArchive = null;
    }
+
+   @Override
    public boolean isClosed() {
        return (zipArchive == null);
    }
 
+   @Override
    public Enumeration<? extends ZipEntry> getEntries() {
       if (zipArchive == null)
          throw new IllegalStateException("Zip File is closed");
@@ -50,10 +57,30 @@ public class ZipFileZipEntrySource imple
       return zipArchive.entries();
    }
 
+   @Override
    public InputStream getInputStream(ZipEntry entry) throws IOException {
       if (zipArchive == null)
          throw new IllegalStateException("Zip File is closed");
       
       return zipArchive.getInputStream(entry);
    }
+
+   @Override
+   public ZipEntry getEntry(final String path) {
+      String normalizedPath = path.replace('\\', '/');
+
+      final ZipEntry entry = zipArchive.getEntry(normalizedPath);
+      if (entry != null) {
+         return entry;
+      }
+
+      // the opc spec allows case-insensitive filename matching (see #49609)
+      for (final ZipEntry ze : asIterable(asIterator(zipArchive.entries()))) {
+         if (normalizedPath.equalsIgnoreCase(ze.getName().replace('\\','/'))) {
+            return ze;
+         }
+      }
+
+      return null;
+   }
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java
 Wed Apr 25 10:03:39 2018
@@ -16,16 +16,14 @@
 ==================================================================== */
 package org.apache.poi.openxml4j.util;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.zip.ZipEntry;
 
-import org.apache.poi.openxml4j.util.ZipSecureFile.ThresholdInputStream;
+import org.apache.commons.collections4.IteratorUtils;
 
 /**
  * Provides a way to get at all the ZipEntries
@@ -36,7 +34,7 @@ import org.apache.poi.openxml4j.util.Zip
  *  done, to free up that memory!
  */
 public class ZipInputStreamZipEntrySource implements ZipEntrySource {
-       private ArrayList<FakeZipEntry> zipEntries;
+       private final Map<String, ZipArchiveFakeEntry> zipEntries = new 
HashMap<>();
        
        /**
         * Reads all the entries from the ZipInputStream 
@@ -44,100 +42,53 @@ public class ZipInputStreamZipEntrySourc
         * We'll then eat lots of memory, but be able to
         *  work with the entries at-will.
         */
-       public ZipInputStreamZipEntrySource(ThresholdInputStream inp) throws 
IOException {
-               zipEntries = new ArrayList<>();
-               
-               boolean going = true;
-               while(going) {
-                       ZipEntry zipEntry = inp.getNextEntry();
-                       if(zipEntry == null) {
-                               going = false;
-                       } else {
-                               FakeZipEntry entry = new FakeZipEntry(zipEntry, 
inp);
-                               inp.closeEntry();
-                               
-                               zipEntries.add(entry);
+       public ZipInputStreamZipEntrySource(ZipArchiveThresholdInputStream inp) 
throws IOException {
+               for (;;) {
+                       final ZipEntry zipEntry = inp.getNextEntry();
+                       if (zipEntry == null) {
+                               break;
                        }
+                       zipEntries.put(zipEntry.getName(), new 
ZipArchiveFakeEntry(zipEntry, inp));
                }
                inp.close();
        }
 
+       @Override
        public Enumeration<? extends ZipEntry> getEntries() {
-               return new EntryEnumerator();
+               return 
IteratorUtils.asEnumeration(zipEntries.values().iterator());
        }
-       
+
+       @Override
        public InputStream getInputStream(ZipEntry zipEntry) {
-           assert (zipEntry instanceof FakeZipEntry);
-               FakeZipEntry entry = (FakeZipEntry)zipEntry;
-               return entry.getInputStream();
+           assert (zipEntry instanceof ZipArchiveFakeEntry);
+               return ((ZipArchiveFakeEntry)zipEntry).getInputStream();
        }
-       
+
+       @Override
        public void close() {
                // Free the memory
-               zipEntries = null;
+               zipEntries.clear();
        }
+
+       @Override
        public boolean isClosed() {
-           return (zipEntries == null);
+           return zipEntries.isEmpty();
        }
-       
-       /**
-        * Why oh why oh why are Iterator and Enumeration
-        *  still not compatible?
-        */
-       private class EntryEnumerator implements Enumeration<ZipEntry> {
-               private Iterator<? extends ZipEntry> iterator;
-               
-               private EntryEnumerator() {
-                       iterator = zipEntries.iterator();
-               }
-               
-               public boolean hasMoreElements() {
-                       return iterator.hasNext();
-               }
 
-               public ZipEntry nextElement() {
-                       return iterator.next();
+       @Override
+       public ZipEntry getEntry(final String path) {
+               final String normalizedPath = path.replace('\\', '/');
+               final ZipEntry ze = zipEntries.get(normalizedPath);
+               if (ze != null) {
+                       return ze;
                }
-       }
 
-       /**
-        * So we can close the real zip entry and still
-        *  effectively work with it.
-        * Holds the (decompressed!) data in memory, so
-        *  close this as soon as you can! 
-        */
-       public static class FakeZipEntry extends ZipEntry {
-               private byte[] data;
-               
-               public FakeZipEntry(ZipEntry entry, InputStream inp) throws 
IOException {
-                       super(entry.getName());
-                       
-                       // Grab the de-compressed contents for later
-            ByteArrayOutputStream baos;
-
-            long entrySize = entry.getSize();
-
-            if (entrySize !=-1) {
-                if (entrySize>=Integer.MAX_VALUE) {
-                    throw new IOException("ZIP entry size is too large");
-                }
-
-                baos = new ByteArrayOutputStream((int) entrySize);
-            } else {
-                       baos = new ByteArrayOutputStream();
-            }
-
-                       byte[] buffer = new byte[4096];
-                       int read = 0;
-                       while( (read = inp.read(buffer)) != -1 ) {
-                               baos.write(buffer, 0, read);
+               for (final Map.Entry<String, ZipArchiveFakeEntry> fze : 
zipEntries.entrySet()) {
+                       if (normalizedPath.equalsIgnoreCase(fze.getKey())) {
+                               return fze.getValue();
                        }
-                       
-                       data = baos.toByteArray();
-               }
-               
-               public InputStream getInputStream() {
-                       return new ByteArrayInputStream(data);
                }
+
+               return null;
        }
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java 
Wed Apr 25 10:03:39 2018
@@ -18,43 +18,27 @@
 package org.apache.poi.openxml4j.util;
 
 import java.io.File;
-import java.io.FilterInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-import java.lang.reflect.Field;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.zip.InflaterInputStream;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
 
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-import org.apache.poi.util.SuppressForbidden;
 
 /**
  * This class wraps a {@link ZipFile} in order to check the
  * entries for <a href="https://en.wikipedia.org/wiki/Zip_bomb";>zip bombs</a>
- * while reading the archive.
- * If a {@link ZipInputStream} is directly used, the wrapper
- * can be applied via {@link #addThreshold(InputStream)}.
+ * while reading the archive.<p>
+ *
  * The alert limits can be globally defined via {@link #setMaxEntrySize(long)}
  * and {@link #setMinInflateRatio(double)}.
  */
 public class ZipSecureFile extends ZipFile {
-    private static final POILogger LOG = 
POILogFactory.getLogger(ZipSecureFile.class);
+    /* package */ static double MIN_INFLATE_RATIO = 0.01d;
+    /* package */ static long MAX_ENTRY_SIZE = 0xFFFFFFFFL;
     
-    private static double MIN_INFLATE_RATIO = 0.01d;
-    private static long MAX_ENTRY_SIZE = 0xFFFFFFFFL;
-    
-    // don't alert for expanded sizes smaller than 100k
-    private final static long GRACE_ENTRY_SIZE = 100*1024L;
-
-    // The default maximum size of extracted text 
+    // The default maximum size of extracted text
     private static long MAX_TEXT_SIZE = 10*1024*1024L;
+
+    private final String fileName;
     
     /**
      * Sets the ratio between de- and inflated bytes to detect zipbomb.
@@ -134,16 +118,14 @@ public class ZipSecureFile extends ZipFi
         return MAX_TEXT_SIZE;
     }
 
-    public ZipSecureFile(File file, int mode) throws ZipException, IOException 
{
-        super(file, mode);
-    }
-
-    public ZipSecureFile(File file) throws ZipException, IOException {
+    public ZipSecureFile(File file) throws IOException {
         super(file);
+        this.fileName = file.getAbsolutePath();
     }
 
-    public ZipSecureFile(String name) throws ZipException, IOException {
+    public ZipSecureFile(String name) throws IOException {
         super(name);
+        this.fileName = new File(name).getAbsolutePath();
     }
 
     /**
@@ -156,176 +138,22 @@ public class ZipSecureFile extends ZipFi
      * @param entry the zip file entry
      * @return the input stream for reading the contents of the specified
      * zip file entry.
-     * @throws ZipException if a ZIP format error has occurred
      * @throws IOException if an I/O error has occurred
      * @throws IllegalStateException if the zip file has been closed
      */
     @Override
     @SuppressWarnings("resource")
-    public InputStream getInputStream(ZipEntry entry) throws IOException {
-        InputStream zipIS = super.getInputStream(entry);
-        return addThreshold(zipIS);
-    }
-
-    public static ThresholdInputStream addThreshold(final InputStream zipIS) 
throws IOException {
-        ThresholdInputStream newInner;
-        if (zipIS instanceof InflaterInputStream) {
-            newInner = AccessController.doPrivileged(new 
PrivilegedAction<ThresholdInputStream>() { // NOSONAR
-                @Override
-                @SuppressForbidden("TODO: Fix this to not use reflection (it 
will break in Java 9)! " +
-                        "Better would be to wrap *before* instead of trying to 
insert wrapper afterwards.")
-                public ThresholdInputStream run() {
-                    try {
-                        Field f = 
FilterInputStream.class.getDeclaredField("in");
-                        f.setAccessible(true);
-                        InputStream oldInner = (InputStream)f.get(zipIS);
-                        ThresholdInputStream newInner2 = new 
ThresholdInputStream(oldInner, null);
-                        f.set(zipIS, newInner2);
-                        return newInner2;
-                    } catch (Exception ex) {
-                        LOG.log(POILogger.WARN, "SecurityManager doesn't allow 
manipulation via reflection for zipbomb detection - continue with original 
input stream", ex);
-                    }
-                    return null;
-                }
-            });
-        } else {
-            // the inner stream is a ZipFileInputStream, i.e. the data wasn't 
compressed
-            newInner = null;
-        }
-
-        return new ThresholdInputStream(zipIS, newInner);
+    public ZipArchiveThresholdInputStream getInputStream(ZipEntry entry) 
throws IOException {
+        ZipArchiveThresholdInputStream zatis = new 
ZipArchiveThresholdInputStream(super.getInputStream(entry));
+        zatis.setEntry(entry);
+        return zatis;
     }
 
-    public static class ThresholdInputStream extends PushbackInputStream {
-        long counter;
-        long markPos;
-        ThresholdInputStream cis;
-
-        public ThresholdInputStream(InputStream is, ThresholdInputStream cis) {
-            super(is);
-            this.cis = cis;
-        }
-
-        @Override
-        public int read() throws IOException {
-            int b = in.read();
-            if (b > -1) {
-                advance(1);
-            }
-            return b;
-        }
-
-        @Override
-        public int read(byte b[], int off, int len) throws IOException {
-            int cnt = in.read(b, off, len);
-            if (cnt > -1) {
-                advance(cnt);
-            }
-            return cnt;
-        }
-
-        @Override
-        public long skip(long n) throws IOException {
-            long s = in.skip(n);
-            counter += s;
-            return s;
-        }
-
-        @Override
-        public synchronized void reset() throws IOException {
-            counter = markPos;
-            super.reset();
-        }
-
-        public void advance(int advance) throws IOException {
-            counter += advance;
-            
-            // check the file size first, in case we are working on 
uncompressed streams
-            if(counter > MAX_ENTRY_SIZE) {
-                throw new IOException("Zip bomb detected! The file would 
exceed the max size of the expanded data in the zip-file. "
-                        + "This may indicates that the file is used to inflate 
memory usage and thus could pose a security risk. "
-                        + "You can adjust this limit via 
ZipSecureFile.setMaxEntrySize() if you need to work with files which are very 
large. "
-                        + "Counter: " + counter + ", cis.counter: " + (cis == 
null ? 0 : cis.counter)
-                        + "Limits: MAX_ENTRY_SIZE: " + MAX_ENTRY_SIZE);
-            }
-
-            // no expanded size?
-            if (cis == null) {
-                return;
-            }
-            
-            // don't alert for small expanded size
-            if (counter <= GRACE_ENTRY_SIZE) {
-                return;
-            }
-
-            double ratio = (double)cis.counter/(double)counter;
-            if (ratio >= MIN_INFLATE_RATIO) {
-                return;
-            }
-
-            // one of the limits was reached, report it
-            throw new IOException("Zip bomb detected! The file would exceed 
the max. ratio of compressed file size to the size of the expanded data.\n"
-                    + "This may indicate that the file is used to inflate 
memory usage and thus could pose a security risk.\n"
-                    + "You can adjust this limit via 
ZipSecureFile.setMinInflateRatio() if you need to work with files which exceed 
this limit.\n"
-                    + "Counter: " + counter + ", cis.counter: " + cis.counter 
+ ", ratio: " + ratio + "\n"
-                    + "Limits: MIN_INFLATE_RATIO: " + MIN_INFLATE_RATIO);
-        }
-
-        public ZipEntry getNextEntry() throws IOException {
-            if (!(in instanceof ZipInputStream)) {
-                throw new UnsupportedOperationException("underlying stream is 
not a ZipInputStream");
-            }
-            counter = 0;
-            return ((ZipInputStream)in).getNextEntry();
-        }
-
-        public void closeEntry() throws IOException {
-            if (!(in instanceof ZipInputStream)) {
-                throw new UnsupportedOperationException("underlying stream is 
not a ZipInputStream");
-            }
-            counter = 0;
-            ((ZipInputStream)in).closeEntry();
-        }
-
-        @Override
-        public void unread(int b) throws IOException {
-            if (!(in instanceof PushbackInputStream)) {
-                throw new UnsupportedOperationException("underlying stream is 
not a PushbackInputStream");
-            }
-            if (--counter < 0) {
-                counter = 0;
-            }
-            ((PushbackInputStream)in).unread(b);
-        }
-
-        @Override
-        public void unread(byte[] b, int off, int len) throws IOException {
-            if (!(in instanceof PushbackInputStream)) {
-                throw new UnsupportedOperationException("underlying stream is 
not a PushbackInputStream");
-            }
-            counter -= len;
-            if (--counter < 0) {
-                counter = 0;
-            }
-            ((PushbackInputStream)in).unread(b, off, len);
-        }
-
-        @Override
-        @SuppressForbidden("just delegating")
-        public int available() throws IOException {
-            return in.available();
-        }
-
-        @Override
-        public boolean markSupported() {
-            return in.markSupported();
-        }
-
-        @Override
-        public synchronized void mark(int readlimit) {
-            markPos = counter;
-            in.mark(readlimit);
-        }
+    /**
+     * Returns the path name of the ZIP file.
+     * @return the path name of the ZIP file
+     */
+    public String getName() {
+        return fileName;
     }
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java
 (original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/AesZipFileZipEntrySource.java
 Wed Apr 25 10:03:39 2018
@@ -53,15 +53,17 @@ import org.apache.poi.util.TempFile;
  * sensitive data is not stored in raw format on disk.
  */
 @Beta
-public class AesZipFileZipEntrySource implements ZipEntrySource {
+public final class AesZipFileZipEntrySource implements ZipEntrySource {
     private static final POILogger LOG = 
POILogFactory.getLogger(AesZipFileZipEntrySource.class);
+
+    private static final String PADDING = "PKCS5Padding";
     
     private final File tmpFile;
     private final ZipFile zipFile;
     private final Cipher ci;
     private boolean closed;
     
-    public AesZipFileZipEntrySource(File tmpFile, Cipher ci) throws 
IOException {
+    private AesZipFileZipEntrySource(File tmpFile, Cipher ci) throws 
IOException {
         this.tmpFile = tmpFile;
         this.zipFile = new ZipFile(tmpFile);
         this.ci = ci;
@@ -76,7 +78,12 @@ public class AesZipFileZipEntrySource im
     public Enumeration<? extends ZipEntry> getEntries() {
         return zipFile.entries();
     }
-    
+
+    @Override
+    public ZipEntry getEntry(String path) {
+        return zipFile.getEntry(path);
+    }
+
     @Override
     public InputStream getInputStream(ZipEntry entry) throws IOException {
         InputStream is = zipFile.getInputStream(entry);
@@ -106,14 +113,14 @@ public class AesZipFileZipEntrySource im
         sr.nextBytes(ivBytes);
         sr.nextBytes(keyBytes);
         final File tmpFile = TempFile.createTempFile("protectedXlsx", ".zip");
-        copyToFile(is, tmpFile, CipherAlgorithm.aes128, keyBytes, ivBytes);
+        copyToFile(is, tmpFile, keyBytes, ivBytes);
         IOUtils.closeQuietly(is);
-        return fileToSource(tmpFile, CipherAlgorithm.aes128, keyBytes, 
ivBytes);
+        return fileToSource(tmpFile, keyBytes, ivBytes);
     }
 
-    private static void copyToFile(InputStream is, File tmpFile, 
CipherAlgorithm cipherAlgorithm, byte keyBytes[], byte ivBytes[]) throws 
IOException, GeneralSecurityException {
-        SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, 
cipherAlgorithm.jceId);
-        Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, 
ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, "PKCS5Padding");
+    private static void copyToFile(InputStream is, File tmpFile, byte 
keyBytes[], byte ivBytes[]) throws IOException, GeneralSecurityException {
+        SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, 
CipherAlgorithm.aes128.jceId);
+        Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, 
CipherAlgorithm.aes128, ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, 
PADDING);
         
         ZipInputStream zis = new ZipInputStream(is);
         FileOutputStream fos = new FileOutputStream(tmpFile);
@@ -146,9 +153,9 @@ public class AesZipFileZipEntrySource im
         zis.close();
     }
 
-    private static AesZipFileZipEntrySource fileToSource(File tmpFile, 
CipherAlgorithm cipherAlgorithm, byte keyBytes[], byte ivBytes[]) throws 
ZipException, IOException {
-        SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, 
cipherAlgorithm.jceId);
-        Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, 
ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, "PKCS5Padding");
+    private static AesZipFileZipEntrySource fileToSource(File tmpFile, byte 
keyBytes[], byte ivBytes[]) throws ZipException, IOException {
+        SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, 
CipherAlgorithm.aes128.jceId);
+        Cipher ciDec = CryptoFunctions.getCipher(skeySpec, 
CipherAlgorithm.aes128, ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, 
PADDING);
         return new AesZipFileZipEntrySource(tmpFile, ciDec);
     }
     

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java 
(original)
+++ 
poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java 
Wed Apr 25 10:03:39 2018
@@ -48,6 +48,7 @@ public class EncryptedTempData {
     private static POILogger LOG = 
POILogFactory.getLogger(EncryptedTempData.class);
  
     private final static CipherAlgorithm cipherAlgorithm = 
CipherAlgorithm.aes128;
+    private final static String PADDING = "PKCS5Padding";
     private final SecretKeySpec skeySpec;
     private final byte[] ivBytes;
     private final File tempFile;
@@ -63,12 +64,12 @@ public class EncryptedTempData {
     }
 
     public OutputStream getOutputStream() throws IOException {
-        Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, 
ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, null);
+        Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, 
ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, PADDING);
         return new CipherOutputStream(new FileOutputStream(tempFile), ciEnc);
     }
 
     public InputStream getInputStream() throws IOException {
-        Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, 
ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, null);
+        Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, 
ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, PADDING);
         return new CipherInputStream(new FileInputStream(tempFile), ciDec);
     }
     

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/dev/XSSFDump.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/dev/XSSFDump.java?rev=1830061&r1=1830060&r2=1830061&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/dev/XSSFDump.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/dev/XSSFDump.java Wed Apr 25 
10:03:39 2018
@@ -24,9 +24,9 @@ import java.io.FileOutputStream;
 import java.io.OutputStream;
 import java.util.Enumeration;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 
 import org.apache.poi.openxml4j.opc.internal.ZipHelper;
+import org.apache.poi.openxml4j.util.ZipSecureFile;
 import org.apache.poi.util.DocumentHelper;
 import org.apache.poi.util.IOUtils;
 import org.apache.xmlbeans.XmlException;
@@ -41,14 +41,13 @@ import org.w3c.dom.Document;
  */
 public final class XSSFDump {
 
+    private XSSFDump() {}
+
     public static void main(String[] args) throws Exception {
-        for (int i = 0; i < args.length; i++) {
-            System.out.println("Dumping " + args[i]);
-            ZipFile zip = ZipHelper.openZipFile(args[i]);
-            try {
+        for (String arg : args) {
+            System.out.println("Dumping " + arg);
+            try (ZipSecureFile zip = ZipHelper.openZipFile(arg)) {
                 dump(zip);
-            } finally {
-                zip.close();
             }
         }
     }
@@ -72,7 +71,7 @@ public final class XSSFDump {
     }
     
 
-    public static void dump(ZipFile zip) throws Exception {
+    public static void dump(ZipSecureFile zip) throws Exception {
         String zipname = zip.getName();
         int sep = zipname.lastIndexOf('.');
         File root = new File(zipname.substring(0, sep));
@@ -90,8 +89,7 @@ public final class XSSFDump {
             }
 
             File f = new File(root, entry.getName());
-            OutputStream out = new FileOutputStream(f);
-            try {
+            try (final OutputStream out = new FileOutputStream(f)) {
                 if (entry.getName().endsWith(".xml") || 
entry.getName().endsWith(".vml") || entry.getName().endsWith(".rels")) {
                     try {
                         Document doc = 
DocumentHelper.readDocument(zip.getInputStream(entry));
@@ -106,8 +104,6 @@ public final class XSSFDump {
                 } else {
                     IOUtils.copy(zip.getInputStream(entry), out);
                 }
-            } finally {
-                out.close();
             }
         }
     }



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

Reply via email to