aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPJ Fanning <fanningpj@apache.org>2021-10-13 18:31:44 +0000
committerPJ Fanning <fanningpj@apache.org>2021-10-13 18:31:44 +0000
commitdefd26493f88bcb3276d0095be81ee74c527b443 (patch)
tree413bc9a22c6044ff147c18b2be4c80ac3351a41a
parent5b7b8ae1a986de24ea3372ea7a013f903b7624eb (diff)
downloadpoi-defd26493f88bcb3276d0095be81ee74c527b443.tar.gz
poi-defd26493f88bcb3276d0095be81ee74c527b443.zip
[bug-65042] support saving package part data in temp files
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894203 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackagePart.java11
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java49
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java2
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/EncryptedTempFilePackagePart.java144
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java22
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/TempFilePackagePart.java142
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFFontData.java2
-rw-r--r--poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java2
8 files changed, 347 insertions, 27 deletions
diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackagePart.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackagePart.java
index 801b700316..2aaf907d5e 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackagePart.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackagePart.java
@@ -518,7 +518,7 @@ public abstract class PackagePart implements RelationshipSource, Comparable<Pack
* @return output stream for this part
* @see org.apache.poi.openxml4j.opc.internal.MemoryPackagePart
*/
- public OutputStream getOutputStream() {
+ public OutputStream getOutputStream() throws IOException {
OutputStream outStream;
// If this part is a zip package part (read only by design) we convert
// this part into a MemoryPackagePart instance for write purpose.
@@ -674,9 +674,8 @@ public abstract class PackagePart implements RelationshipSource, Comparable<Pack
* Method that gets the input stream for this part.
*
* @return input stream for this part
- * @exception IOException
- * Throws if an IO Exception occur in the implementation
- * method.
+ * @throws IOException
+ * Throws if an IO Exception occur in the implementation method.
*/
protected abstract InputStream getInputStreamImpl() throws IOException;
@@ -684,8 +683,10 @@ public abstract class PackagePart implements RelationshipSource, Comparable<Pack
* Method that gets the output stream for this part.
*
* @return output stream for this part
+ * @throws IOException
+ * Throws if an IO Exception occur in the implementation method.
*/
- protected abstract OutputStream getOutputStreamImpl();
+ protected abstract OutputStream getOutputStreamImpl() throws IOException;
/**
* Save the content of this part and the associated relationships part (if
diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java
index 1ee1961de7..00cde38505 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackage.java
@@ -43,12 +43,7 @@ import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
import org.apache.poi.openxml4j.exceptions.ODFNotOfficeXmlFileException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
-import org.apache.poi.openxml4j.opc.internal.ContentTypeManager;
-import org.apache.poi.openxml4j.opc.internal.FileHelper;
-import org.apache.poi.openxml4j.opc.internal.MemoryPackagePart;
-import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
-import org.apache.poi.openxml4j.opc.internal.ZipContentTypeManager;
-import org.apache.poi.openxml4j.opc.internal.ZipHelper;
+import org.apache.poi.openxml4j.opc.internal.*;
import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream;
import org.apache.poi.openxml4j.util.ZipEntrySource;
@@ -63,6 +58,8 @@ import org.apache.poi.util.TempFile;
public final class ZipPackage extends OPCPackage {
private static final String MIMETYPE = "mimetype";
private static final String SETTINGS_XML = "settings.xml";
+ private static boolean useTempFilePackageParts = false;
+ private static boolean encryptTempFilePackageParts = false;
private static final Logger LOG = LogManager.getLogger(ZipPackage.class);
@@ -73,6 +70,34 @@ public final class ZipPackage extends OPCPackage {
private final ZipEntrySource zipArchive;
/**
+ * @param tempFilePackageParts whether to save package part data in temp files to save memory
+ */
+ public void setUseTempFilePackageParts(boolean tempFilePackageParts) {
+ useTempFilePackageParts = tempFilePackageParts;
+ }
+
+ /**
+ * @param encryptTempFiles whether to encrypt temp files
+ */
+ public void setEncryptTempFilePackageParts(boolean encryptTempFiles) {
+ encryptTempFilePackageParts = encryptTempFiles;
+ }
+
+ /**
+ * @return whether package part data is stored in temp files to save memory
+ */
+ public boolean useTempFilePackageParts() {
+ return useTempFilePackageParts;
+ }
+
+ /**
+ * @return whether package part temp files are encrypted
+ */
+ public boolean encryptTempFilePackageParts() {
+ return encryptTempFilePackageParts;
+ }
+
+ /**
* Constructor. Creates a new, empty ZipPackage.
*/
public ZipPackage() {
@@ -371,8 +396,16 @@ public final class ZipPackage extends OPCPackage {
}
try {
- return new MemoryPackagePart(this, partName, contentType, loadRelationships);
- } catch (InvalidFormatException e) {
+ if (useTempFilePackageParts) {
+ if (encryptTempFilePackageParts) {
+ return new EncryptedTempFilePackagePart(this, partName, contentType, loadRelationships);
+ } else {
+ return new TempFilePackagePart(this, partName, contentType, loadRelationships);
+ }
+ } else {
+ return new MemoryPackagePart(this, partName, contentType, loadRelationships);
+ }
+ } catch (Exception e) {
LOG.atWarn().withThrowable(e).log("Failed to create part {}", partName);
return null;
}
diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java
index fd862a0d7f..3ca7adbe0b 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java
@@ -86,7 +86,7 @@ public class ZipPackagePart extends PackagePart {
/**
* Get the zip entry of this part.
*
- * @return The zip entry in the zip structure coresponding to this part.
+ * @return The zip entry in the zip structure corresponding to this part.
*/
public ZipArchiveEntry getZipArchive() {
return zipEntry;
diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/EncryptedTempFilePackagePart.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/EncryptedTempFilePackagePart.java
new file mode 100644
index 0000000000..a9119eaf42
--- /dev/null
+++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/EncryptedTempFilePackagePart.java
@@ -0,0 +1,144 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc.internal;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
+import org.apache.poi.poifs.crypt.temp.EncryptedTempData;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.TempFile;
+
+import java.io.*;
+
+/**
+ * (Experimental) Encrypted Temp File version of a package part.
+ *
+ * @since POI 5.1.0
+ */
+@Beta
+public final class EncryptedTempFilePackagePart extends PackagePart {
+ private static final Logger LOG = LogManager.getLogger(EncryptedTempFilePackagePart.class);
+
+ /**
+ * Storage for the part data.
+ */
+ private EncryptedTempData tempFile;
+
+ /**
+ * Constructor.
+ *
+ * @param pack
+ * The owner package.
+ * @param partName
+ * The part name.
+ * @param contentType
+ * The content type.
+ * @throws InvalidFormatException
+ * If the specified URI is not OPC compliant.
+ * @throws IOException
+ * If temp file cannot be created.
+ */
+ public EncryptedTempFilePackagePart(OPCPackage pack, PackagePartName partName,
+ String contentType) throws InvalidFormatException, IOException {
+ this(pack, partName, contentType, false);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param pack
+ * The owner package.
+ * @param partName
+ * The part name.
+ * @param contentType
+ * The content type.
+ * @param loadRelationships
+ * Specify if the relationships will be loaded.
+ * @throws InvalidFormatException
+ * If the specified URI is not OPC compliant.
+ * @throws IOException
+ * If temp file cannot be created.
+ */
+ public EncryptedTempFilePackagePart(OPCPackage pack, PackagePartName partName,
+ String contentType, boolean loadRelationships)
+ throws InvalidFormatException, IOException {
+ super(pack, partName, new ContentType(contentType), loadRelationships);
+ tempFile = new EncryptedTempData();
+ }
+
+ @Override
+ protected InputStream getInputStreamImpl() throws IOException {
+ return tempFile.getInputStream();
+ }
+
+ @Override
+ protected OutputStream getOutputStreamImpl() throws IOException {
+ return tempFile.getOutputStream();
+ }
+
+ /**
+ * @return EncryptedTempData.getSize() always returns -1
+ */
+ @Override
+ public long getSize() {
+ return -1;
+ }
+
+ @Override
+ public void clear() {
+ try(OutputStream os = getOutputStreamImpl()) {
+ os.write(new byte[0]);
+ } catch (IOException e) {
+ LOG.atWarn().log("Failed to clear data in temp file", e);
+ }
+ }
+
+ @Override
+ public boolean save(OutputStream os) throws OpenXML4JException {
+ return new ZipPartMarshaller().marshall(this, os);
+ }
+
+ @Override
+ public boolean load(InputStream ios) throws InvalidFormatException {
+ try (OutputStream os = getOutputStreamImpl()) {
+ IOUtils.copy(ios, os);
+ } catch(IOException e) {
+ throw new InvalidFormatException(e.getMessage(), e);
+ }
+
+ // All done
+ return true;
+ }
+
+ @Override
+ public void close() {
+ tempFile.dispose();
+ }
+
+ @Override
+ public void flush() {
+ // Do nothing
+ }
+}
diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java
index 0454afee02..d7f7a2dcf7 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java
@@ -113,17 +113,17 @@ public final class MemoryPackagePart extends PackagePart {
@Override
public boolean load(InputStream ios) throws InvalidFormatException {
- try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
- // Grab the data
- IOUtils.copy(ios, baos);
- // Save it
- data = baos.toByteArray();
- } catch(IOException e) {
- throw new InvalidFormatException(e.getMessage());
- }
-
- // All done
- return true;
+ try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
+ // Grab the data
+ IOUtils.copy(ios, baos);
+ // Save it
+ data = baos.toByteArray();
+ } catch (IOException e) {
+ throw new InvalidFormatException(e.getMessage());
+ }
+
+ // All done
+ return true;
}
@Override
diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/TempFilePackagePart.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/TempFilePackagePart.java
new file mode 100644
index 0000000000..f3e1fc157f
--- /dev/null
+++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/TempFilePackagePart.java
@@ -0,0 +1,142 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc.internal;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.TempFile;
+
+import java.io.*;
+
+/**
+ * (Experimental) Temp File version of a package part.
+ *
+ * @since POI 5.1.0
+ */
+@Beta
+public final class TempFilePackagePart extends PackagePart {
+ private static final Logger LOG = LogManager.getLogger(TempFilePackagePart.class);
+
+ /**
+ * Storage for the part data.
+ */
+ private File tempFile;
+
+ /**
+ * Constructor.
+ *
+ * @param pack
+ * The owner package.
+ * @param partName
+ * The part name.
+ * @param contentType
+ * The content type.
+ * @throws InvalidFormatException
+ * If the specified URI is not OPC compliant.
+ * @throws IOException
+ * If temp file cannot be created.
+ */
+ public TempFilePackagePart(OPCPackage pack, PackagePartName partName,
+ String contentType) throws InvalidFormatException, IOException {
+ this(pack, partName, contentType, false);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param pack
+ * The owner package.
+ * @param partName
+ * The part name.
+ * @param contentType
+ * The content type.
+ * @param loadRelationships
+ * Specify if the relationships will be loaded.
+ * @throws InvalidFormatException
+ * If the specified URI is not OPC compliant.
+ * @throws IOException
+ * If temp file cannot be created.
+ */
+ public TempFilePackagePart(OPCPackage pack, PackagePartName partName,
+ String contentType, boolean loadRelationships)
+ throws InvalidFormatException, IOException {
+ super(pack, partName, new ContentType(contentType), loadRelationships);
+ tempFile = TempFile.createTempFile("poi-package-part", ".tmp");
+ }
+
+ @Override
+ protected InputStream getInputStreamImpl() throws IOException {
+ return new FileInputStream(tempFile);
+ }
+
+ @Override
+ protected OutputStream getOutputStreamImpl() throws IOException {
+ return new FileOutputStream(tempFile);
+ }
+
+ @Override
+ public long getSize() {
+ return tempFile.length();
+ }
+
+ @Override
+ public void clear() {
+ try(OutputStream os = getOutputStreamImpl()) {
+ os.write(new byte[0]);
+ } catch (IOException e) {
+ LOG.atWarn().log("Failed to clear data in temp file", e);
+ }
+ }
+
+ @Override
+ public boolean save(OutputStream os) throws OpenXML4JException {
+ return new ZipPartMarshaller().marshall(this, os);
+ }
+
+ @Override
+ public boolean load(InputStream ios) throws InvalidFormatException {
+ try (OutputStream os = getOutputStreamImpl()) {
+ IOUtils.copy(ios, os);
+ } catch(IOException e) {
+ throw new InvalidFormatException(e.getMessage(), e);
+ }
+
+ // All done
+ return true;
+ }
+
+ @Override
+ public void close() {
+ if (!tempFile.delete()) {
+ LOG.atInfo().log("Failed to delete temp file; may already have been closed and deleted");
+ }
+ }
+
+ @Override
+ public void flush() {
+ // Do nothing
+ }
+}
diff --git a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFFontData.java b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFFontData.java
index 8b2cb09ebc..0c2e5efa29 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFFontData.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFFontData.java
@@ -57,7 +57,7 @@ public class XSLFFontData extends POIXMLDocumentPart {
return getPackagePart().getInputStream();
}
- public OutputStream getOutputStream() {
+ public OutputStream getOutputStream() throws IOException {
final PackagePart pp = getPackagePart();
pp.clear();
return pp.getOutputStream();
diff --git a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java
index 09125fe585..dee50bc116 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java
@@ -59,7 +59,7 @@ public final class XSLFObjectData extends POIXMLDocumentPart implements ObjectDa
}
@Override
- public OutputStream getOutputStream() {
+ public OutputStream getOutputStream() throws IOException {
final PackagePart pp = getPackagePart();
pp.clear();
return pp.getOutputStream();