diff options
author | PJ Fanning <fanningpj@apache.org> | 2021-10-13 18:31:44 +0000 |
---|---|---|
committer | PJ Fanning <fanningpj@apache.org> | 2021-10-13 18:31:44 +0000 |
commit | defd26493f88bcb3276d0095be81ee74c527b443 (patch) | |
tree | 413bc9a22c6044ff147c18b2be4c80ac3351a41a | |
parent | 5b7b8ae1a986de24ea3372ea7a013f903b7624eb (diff) | |
download | poi-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
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(); |