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]