mirror of https://github.com/apache/poi.git
[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
This commit is contained in:
parent
5b7b8ae1a9
commit
defd26493f
|
@ -518,7 +518,7 @@ public abstract class PackagePart implements RelationshipSource, Comparable<Pack
|
||||||
* @return output stream for this part
|
* @return output stream for this part
|
||||||
* @see org.apache.poi.openxml4j.opc.internal.MemoryPackagePart
|
* @see org.apache.poi.openxml4j.opc.internal.MemoryPackagePart
|
||||||
*/
|
*/
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
OutputStream outStream;
|
OutputStream outStream;
|
||||||
// If this part is a zip package part (read only by design) we convert
|
// If this part is a zip package part (read only by design) we convert
|
||||||
// this part into a MemoryPackagePart instance for write purpose.
|
// 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.
|
* Method that gets the input stream for this part.
|
||||||
*
|
*
|
||||||
* @return input stream for this part
|
* @return input stream for this part
|
||||||
* @exception IOException
|
* @throws IOException
|
||||||
* Throws if an IO Exception occur in the implementation
|
* Throws if an IO Exception occur in the implementation method.
|
||||||
* method.
|
|
||||||
*/
|
*/
|
||||||
protected abstract InputStream getInputStreamImpl() throws IOException;
|
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.
|
* Method that gets the output stream for this part.
|
||||||
*
|
*
|
||||||
* @return 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
|
* Save the content of this part and the associated relationships part (if
|
||||||
|
|
|
@ -43,12 +43,7 @@ import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
|
||||||
import org.apache.poi.openxml4j.exceptions.ODFNotOfficeXmlFileException;
|
import org.apache.poi.openxml4j.exceptions.ODFNotOfficeXmlFileException;
|
||||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
||||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
|
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
|
||||||
import org.apache.poi.openxml4j.opc.internal.ContentTypeManager;
|
import org.apache.poi.openxml4j.opc.internal.*;
|
||||||
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.marshallers.ZipPartMarshaller;
|
import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
|
||||||
import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream;
|
import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream;
|
||||||
import org.apache.poi.openxml4j.util.ZipEntrySource;
|
import org.apache.poi.openxml4j.util.ZipEntrySource;
|
||||||
|
@ -63,6 +58,8 @@ import org.apache.poi.util.TempFile;
|
||||||
public final class ZipPackage extends OPCPackage {
|
public final class ZipPackage extends OPCPackage {
|
||||||
private static final String MIMETYPE = "mimetype";
|
private static final String MIMETYPE = "mimetype";
|
||||||
private static final String SETTINGS_XML = "settings.xml";
|
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);
|
private static final Logger LOG = LogManager.getLogger(ZipPackage.class);
|
||||||
|
|
||||||
|
@ -72,6 +69,34 @@ public final class ZipPackage extends OPCPackage {
|
||||||
*/
|
*/
|
||||||
private final ZipEntrySource zipArchive;
|
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.
|
* Constructor. Creates a new, empty ZipPackage.
|
||||||
*/
|
*/
|
||||||
|
@ -371,8 +396,16 @@ public final class ZipPackage extends OPCPackage {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new MemoryPackagePart(this, partName, contentType, loadRelationships);
|
if (useTempFilePackageParts) {
|
||||||
} catch (InvalidFormatException e) {
|
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);
|
LOG.atWarn().withThrowable(e).log("Failed to create part {}", partName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class ZipPackagePart extends PackagePart {
|
||||||
/**
|
/**
|
||||||
* Get the zip entry of this part.
|
* 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() {
|
public ZipArchiveEntry getZipArchive() {
|
||||||
return zipEntry;
|
return zipEntry;
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -113,17 +113,17 @@ public final class MemoryPackagePart extends PackagePart {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean load(InputStream ios) throws InvalidFormatException {
|
public boolean load(InputStream ios) throws InvalidFormatException {
|
||||||
try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
|
try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
// Grab the data
|
// Grab the data
|
||||||
IOUtils.copy(ios, baos);
|
IOUtils.copy(ios, baos);
|
||||||
// Save it
|
// Save it
|
||||||
data = baos.toByteArray();
|
data = baos.toByteArray();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidFormatException(e.getMessage());
|
throw new InvalidFormatException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// All done
|
// All done
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,7 +57,7 @@ public class XSLFFontData extends POIXMLDocumentPart {
|
||||||
return getPackagePart().getInputStream();
|
return getPackagePart().getInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
final PackagePart pp = getPackagePart();
|
final PackagePart pp = getPackagePart();
|
||||||
pp.clear();
|
pp.clear();
|
||||||
return pp.getOutputStream();
|
return pp.getOutputStream();
|
||||||
|
|
|
@ -59,7 +59,7 @@ public final class XSLFObjectData extends POIXMLDocumentPart implements ObjectDa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
final PackagePart pp = getPackagePart();
|
final PackagePart pp = getPackagePart();
|
||||||
pp.clear();
|
pp.clear();
|
||||||
return pp.getOutputStream();
|
return pp.getOutputStream();
|
||||||
|
|
Loading…
Reference in New Issue