Bug 56865 - Limit number of bytes (by counting them) while opening office docs
Bug 50090 - 'zip' bomb prevention git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1687148 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
057768994e
commit
c0cb680292
@ -23,6 +23,7 @@ import java.util.zip.ZipEntry;
|
|||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
|
||||||
import org.apache.poi.ss.usermodel.DateUtil;
|
import org.apache.poi.ss.usermodel.DateUtil;
|
||||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
@ -165,7 +166,7 @@ public class BigGridDemo {
|
|||||||
* @param out the stream to write the result to
|
* @param out the stream to write the result to
|
||||||
*/
|
*/
|
||||||
private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
|
private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
|
||||||
ZipFile zip = new ZipFile(zipfile);
|
ZipFile zip = ZipHelper.openZipFile(zipfile);
|
||||||
|
|
||||||
ZipOutputStream zos = new ZipOutputStream(out);
|
ZipOutputStream zos = new ZipOutputStream(out);
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ import javax.xml.transform.TransformerFactory;
|
|||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
|
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
@ -82,7 +83,7 @@ public class OOXMLPrettyPrint {
|
|||||||
IOException, TransformerException, ParserConfigurationException {
|
IOException, TransformerException, ParserConfigurationException {
|
||||||
System.out.println("Reading zip-file " + file + " and writing pretty-printed XML to " + outFile);
|
System.out.println("Reading zip-file " + file + " and writing pretty-printed XML to " + outFile);
|
||||||
|
|
||||||
ZipFile zipFile = new ZipFile(file);
|
ZipFile zipFile = ZipHelper.openZipFile(file);
|
||||||
try {
|
try {
|
||||||
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)));
|
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)));
|
||||||
try {
|
try {
|
||||||
|
@ -41,6 +41,8 @@ import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
|
|||||||
import org.apache.poi.openxml4j.util.ZipEntrySource;
|
import org.apache.poi.openxml4j.util.ZipEntrySource;
|
||||||
import org.apache.poi.openxml4j.util.ZipFileZipEntrySource;
|
import org.apache.poi.openxml4j.util.ZipFileZipEntrySource;
|
||||||
import org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource;
|
import org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource;
|
||||||
|
import org.apache.poi.openxml4j.util.ZipSecureFile;
|
||||||
|
import org.apache.poi.openxml4j.util.ZipSecureFile.ThresholdInputStream;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
import org.apache.poi.util.TempFile;
|
import org.apache.poi.util.TempFile;
|
||||||
@ -85,9 +87,9 @@ public final class ZipPackage extends Package {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
ZipPackage(InputStream in, PackageAccess access) throws IOException {
|
ZipPackage(InputStream in, PackageAccess access) throws IOException {
|
||||||
super(access);
|
super(access);
|
||||||
this.zipArchive = new ZipInputStreamZipEntrySource(
|
InputStream zis = new ZipInputStream(in);
|
||||||
new ZipInputStream(in)
|
ThresholdInputStream tis = ZipSecureFile.addThreshold(zis);
|
||||||
);
|
this.zipArchive = new ZipInputStreamZipEntrySource(tis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +29,7 @@ import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
|||||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||||
import org.apache.poi.openxml4j.opc.ZipPackage;
|
import org.apache.poi.openxml4j.opc.ZipPackage;
|
||||||
|
import org.apache.poi.openxml4j.util.ZipSecureFile;
|
||||||
|
|
||||||
public final class ZipHelper {
|
public final class ZipHelper {
|
||||||
|
|
||||||
@ -154,7 +155,7 @@ public final class ZipHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ZipFile(file);
|
return new ZipSecureFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,6 +172,6 @@ public final class ZipHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ZipFile(f);
|
return new ZipSecureFile(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ import java.util.Iterator;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import org.apache.poi.openxml4j.util.ZipSecureFile.ThresholdInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a way to get at all the ZipEntries
|
* Provides a way to get at all the ZipEntries
|
||||||
* from a ZipInputStream, as many times as required.
|
* from a ZipInputStream, as many times as required.
|
||||||
@ -43,7 +45,7 @@ public class ZipInputStreamZipEntrySource implements ZipEntrySource {
|
|||||||
* We'll then eat lots of memory, but be able to
|
* We'll then eat lots of memory, but be able to
|
||||||
* work with the entries at-will.
|
* work with the entries at-will.
|
||||||
*/
|
*/
|
||||||
public ZipInputStreamZipEntrySource(ZipInputStream inp) throws IOException {
|
public ZipInputStreamZipEntrySource(ThresholdInputStream inp) throws IOException {
|
||||||
zipEntries = new ArrayList<FakeZipEntry>();
|
zipEntries = new ArrayList<FakeZipEntry>();
|
||||||
|
|
||||||
boolean going = true;
|
boolean going = true;
|
||||||
@ -105,7 +107,7 @@ public class ZipInputStreamZipEntrySource implements ZipEntrySource {
|
|||||||
public static class FakeZipEntry extends ZipEntry {
|
public static class FakeZipEntry extends ZipEntry {
|
||||||
private byte[] data;
|
private byte[] data;
|
||||||
|
|
||||||
public FakeZipEntry(ZipEntry entry, ZipInputStream inp) throws IOException {
|
public FakeZipEntry(ZipEntry entry, InputStream inp) throws IOException {
|
||||||
super(entry.getName());
|
super(entry.getName());
|
||||||
|
|
||||||
// Grab the de-compressed contents for later
|
// Grab the de-compressed contents for later
|
||||||
|
227
src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java
Normal file
227
src/ooxml/java/org/apache/poi/openxml4j/util/ZipSecureFile.java
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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.File;
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PushbackInputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)}.
|
||||||
|
* The alert limits can be globally defined via {@link #setMaxEntrySize(long)}
|
||||||
|
* and {@link #setMinInflateRatio(double)}.
|
||||||
|
*/
|
||||||
|
public class ZipSecureFile extends ZipFile {
|
||||||
|
private static POILogger logger = POILogFactory.getLogger(ZipSecureFile.class);
|
||||||
|
|
||||||
|
private static double MIN_INFLATE_RATIO = 0.01d;
|
||||||
|
private static long MAX_ENTRY_SIZE = 0xFFFFFFFFl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ratio between de- and inflated bytes to detect zipbomb.
|
||||||
|
* It defaults to 1% (= 0.01d), i.e. when the compression is better than
|
||||||
|
* 1% for any given read package part, the parsing will fail
|
||||||
|
*
|
||||||
|
* @param ratio the ratio between de- and inflated bytes to detect zipbomb
|
||||||
|
*/
|
||||||
|
public static void setMinInflateRatio(double ratio) {
|
||||||
|
MIN_INFLATE_RATIO = ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum file size of a single zip entry. It defaults to 4GB,
|
||||||
|
* i.e. the 32-bit zip format maximum.
|
||||||
|
*
|
||||||
|
* @param maxEntrySize the max. file size of a single zip entry
|
||||||
|
*/
|
||||||
|
public static void setMaxEntrySize(long maxEntrySize) {
|
||||||
|
if (maxEntrySize < 0 || maxEntrySize > 0xFFFFFFFFl) {
|
||||||
|
throw new IllegalArgumentException("Max entry size is bounded [0-4GB].");
|
||||||
|
}
|
||||||
|
MAX_ENTRY_SIZE = maxEntrySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipSecureFile(File file, Charset charset) throws IOException {
|
||||||
|
super(file, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipSecureFile(File file, int mode, Charset charset) throws IOException {
|
||||||
|
super(file, mode, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipSecureFile(File file, int mode) throws IOException {
|
||||||
|
super(file, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipSecureFile(File file) throws ZipException, IOException {
|
||||||
|
super(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipSecureFile(String name, Charset charset) throws IOException {
|
||||||
|
super(name, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipSecureFile(String name) throws IOException {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an input stream for reading the contents of the specified
|
||||||
|
* zip file entry.
|
||||||
|
*
|
||||||
|
* <p> Closing this ZIP file will, in turn, close all input
|
||||||
|
* streams that have been returned by invocations of this method.
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream(ZipEntry entry) throws IOException {
|
||||||
|
InputStream zipIS = super.getInputStream(entry);
|
||||||
|
return addThreshold(zipIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ThresholdInputStream addThreshold(InputStream zipIS) throws IOException {
|
||||||
|
ThresholdInputStream newInner;
|
||||||
|
if (zipIS instanceof InflaterInputStream) {
|
||||||
|
try {
|
||||||
|
Field f = FilterInputStream.class.getDeclaredField("in");
|
||||||
|
f.setAccessible(true);
|
||||||
|
InputStream oldInner = (InputStream)f.get(zipIS);
|
||||||
|
newInner = new ThresholdInputStream(oldInner, null);
|
||||||
|
f.set(zipIS, newInner);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(POILogger.WARN, "SecurityManager doesn't allow manipulation via reflection for zipbomb detection - continue with original input stream", ex);
|
||||||
|
newInner = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the inner stream is a ZipFileInputStream, i.e. the data wasn't compressed
|
||||||
|
newInner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ThresholdInputStream(zipIS, newInner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ThresholdInputStream extends PushbackInputStream {
|
||||||
|
long counter = 0;
|
||||||
|
ThresholdInputStream cis;
|
||||||
|
|
||||||
|
public ThresholdInputStream(InputStream is, ThresholdInputStream cis) {
|
||||||
|
super(is,1);
|
||||||
|
this.cis = cis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read() throws IOException {
|
||||||
|
int b = in.read();
|
||||||
|
if (b > -1) advance(1);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
counter = 0;
|
||||||
|
return in.skip(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void reset() throws IOException {
|
||||||
|
counter = 0;
|
||||||
|
in.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) {
|
||||||
|
if (cis == null) return;
|
||||||
|
double ratio = (double)cis.counter/(double)counter;
|
||||||
|
if (ratio > MIN_INFLATE_RATIO) return;
|
||||||
|
}
|
||||||
|
throw new IOException("Zip bomb detected! Exiting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int available() throws IOException {
|
||||||
|
return in.available();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean markSupported() {
|
||||||
|
return in.markSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void mark(int readlimit) {
|
||||||
|
in.mark(readlimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ import java.util.Enumeration;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import org.apache.xmlbeans.XmlOptions;
|
import org.apache.xmlbeans.XmlOptions;
|
||||||
@ -38,7 +39,7 @@ public final class XSSFDump {
|
|||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
System.out.println("Dumping " + args[i]);
|
System.out.println("Dumping " + args[i]);
|
||||||
ZipFile zip = new ZipFile(args[i]);
|
ZipFile zip = ZipHelper.openZipFile(args[i]);
|
||||||
try {
|
try {
|
||||||
dump(zip);
|
dump(zip);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -32,6 +32,7 @@ import java.util.zip.ZipFile;
|
|||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||||
|
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
|
||||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||||
import org.apache.poi.ss.usermodel.CellStyle;
|
import org.apache.poi.ss.usermodel.CellStyle;
|
||||||
import org.apache.poi.ss.usermodel.CreationHelper;
|
import org.apache.poi.ss.usermodel.CreationHelper;
|
||||||
@ -334,7 +335,7 @@ public class SXSSFWorkbook implements Workbook
|
|||||||
}
|
}
|
||||||
private void injectData(File zipfile, OutputStream out) throws IOException
|
private void injectData(File zipfile, OutputStream out) throws IOException
|
||||||
{
|
{
|
||||||
ZipFile zip = new ZipFile(zipfile);
|
ZipFile zip = ZipHelper.openZipFile(zipfile);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ZipOutputStream zos = new ZipOutputStream(out);
|
ZipOutputStream zos = new ZipOutputStream(out);
|
||||||
|
@ -17,28 +17,24 @@
|
|||||||
|
|
||||||
package org.apache.poi.openxml4j.opc;
|
package org.apache.poi.openxml4j.opc;
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
import org.apache.poi.openxml4j.opc.compliance.AllOpenXML4JComplianceTests;
|
import org.apache.poi.openxml4j.opc.compliance.AllOpenXML4JComplianceTests;
|
||||||
import org.apache.poi.openxml4j.opc.internal.AllOpenXML4JInternalTests;
|
import org.apache.poi.openxml4j.opc.internal.AllOpenXML4JInternalTests;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Suite;
|
||||||
|
|
||||||
|
@RunWith(Suite.class)
|
||||||
|
@Suite.SuiteClasses({
|
||||||
|
TestContentType.class
|
||||||
|
, TestFileHelper.class
|
||||||
|
, TestListParts.class
|
||||||
|
, TestPackage.class
|
||||||
|
, TestPackageCoreProperties.class
|
||||||
|
, TestPackagePartName.class
|
||||||
|
, TestPackageThumbnail.class
|
||||||
|
, TestPackagingURIHelper.class
|
||||||
|
, TestRelationships.class
|
||||||
|
, AllOpenXML4JComplianceTests.class
|
||||||
|
, AllOpenXML4JInternalTests.class
|
||||||
|
})
|
||||||
public final class AllOpenXML4JTests {
|
public final class AllOpenXML4JTests {
|
||||||
|
|
||||||
public static Test suite() {
|
|
||||||
|
|
||||||
TestSuite suite = new TestSuite(AllOpenXML4JTests.class.getName());
|
|
||||||
suite.addTestSuite(TestContentType.class);
|
|
||||||
suite.addTestSuite(TestFileHelper.class);
|
|
||||||
suite.addTestSuite(TestListParts.class);
|
|
||||||
suite.addTestSuite(TestPackage.class);
|
|
||||||
suite.addTestSuite(TestPackageCoreProperties.class);
|
|
||||||
suite.addTestSuite(TestPackagePartName.class);
|
|
||||||
suite.addTestSuite(TestPackageThumbnail.class);
|
|
||||||
suite.addTestSuite(TestPackagingURIHelper.class);
|
|
||||||
suite.addTestSuite(TestRelationships.class);
|
|
||||||
suite.addTest(AllOpenXML4JComplianceTests.suite());
|
|
||||||
suite.addTest(AllOpenXML4JInternalTests.suite());
|
|
||||||
return suite;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,14 @@
|
|||||||
|
|
||||||
package org.apache.poi.openxml4j.opc;
|
package org.apache.poi.openxml4j.opc;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@ -25,35 +33,47 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import org.apache.poi.POIXMLException;
|
||||||
|
|
||||||
import org.apache.poi.openxml4j.OpenXML4JTestDataSamples;
|
import org.apache.poi.openxml4j.OpenXML4JTestDataSamples;
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
|
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
|
||||||
import org.apache.poi.openxml4j.opc.internal.ContentTypeManager;
|
import org.apache.poi.openxml4j.opc.internal.ContentTypeManager;
|
||||||
import org.apache.poi.openxml4j.opc.internal.FileHelper;
|
import org.apache.poi.openxml4j.opc.internal.FileHelper;
|
||||||
import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
|
import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
|
||||||
|
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
|
||||||
|
import org.apache.poi.openxml4j.util.ZipSecureFile;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||||
import org.apache.poi.util.DocumentHelper;
|
import org.apache.poi.util.DocumentHelper;
|
||||||
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
import org.apache.poi.util.TempFile;
|
import org.apache.poi.util.TempFile;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
public final class TestPackage extends TestCase {
|
public final class TestPackage {
|
||||||
private static final POILogger logger = POILogFactory.getLogger(TestPackage.class);
|
private static final POILogger logger = POILogFactory.getLogger(TestPackage.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that just opening and closing the file doesn't alter the document.
|
* Test that just opening and closing the file doesn't alter the document.
|
||||||
*/
|
*/
|
||||||
public void testOpenSave() throws Exception {
|
@Test
|
||||||
|
public void openSave() throws Exception {
|
||||||
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
||||||
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageOpenSaveTMP.docx");
|
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageOpenSaveTMP.docx");
|
||||||
|
|
||||||
@ -75,7 +95,8 @@ public final class TestPackage extends TestCase {
|
|||||||
* Test that when we create a new Package, we give it
|
* Test that when we create a new Package, we give it
|
||||||
* the correct default content types
|
* the correct default content types
|
||||||
*/
|
*/
|
||||||
public void testCreateGetsContentTypes() throws Exception {
|
@Test
|
||||||
|
public void createGetsContentTypes() throws Exception {
|
||||||
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestCreatePackageTMP.docx");
|
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestCreatePackageTMP.docx");
|
||||||
|
|
||||||
// Zap the target file, in case of an earlier run
|
// Zap the target file, in case of an earlier run
|
||||||
@ -107,7 +128,8 @@ public final class TestPackage extends TestCase {
|
|||||||
/**
|
/**
|
||||||
* Test package creation.
|
* Test package creation.
|
||||||
*/
|
*/
|
||||||
public void testCreatePackageAddPart() throws Exception {
|
@Test
|
||||||
|
public void createPackageAddPart() throws Exception {
|
||||||
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestCreatePackageTMP.docx");
|
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestCreatePackageTMP.docx");
|
||||||
|
|
||||||
File expectedFile = OpenXML4JTestDataSamples.getSampleFile("TestCreatePackageOUTPUT.docx");
|
File expectedFile = OpenXML4JTestDataSamples.getSampleFile("TestCreatePackageOUTPUT.docx");
|
||||||
@ -153,7 +175,8 @@ public final class TestPackage extends TestCase {
|
|||||||
* document and another part, save and re-load and
|
* document and another part, save and re-load and
|
||||||
* have everything setup as expected
|
* have everything setup as expected
|
||||||
*/
|
*/
|
||||||
public void testCreatePackageWithCoreDocument() throws Exception {
|
@Test
|
||||||
|
public void createPackageWithCoreDocument() throws Exception {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
OPCPackage pkg = OPCPackage.create(baos);
|
OPCPackage pkg = OPCPackage.create(baos);
|
||||||
|
|
||||||
@ -247,7 +270,8 @@ public final class TestPackage extends TestCase {
|
|||||||
/**
|
/**
|
||||||
* Test package opening.
|
* Test package opening.
|
||||||
*/
|
*/
|
||||||
public void testOpenPackage() throws Exception {
|
@Test
|
||||||
|
public void openPackage() throws Exception {
|
||||||
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestOpenPackageTMP.docx");
|
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestOpenPackageTMP.docx");
|
||||||
|
|
||||||
File inputFile = OpenXML4JTestDataSamples.getSampleFile("TestOpenPackageINPUT.docx");
|
File inputFile = OpenXML4JTestDataSamples.getSampleFile("TestOpenPackageINPUT.docx");
|
||||||
@ -306,7 +330,8 @@ public final class TestPackage extends TestCase {
|
|||||||
* OutputStream, in addition to the normal writing
|
* OutputStream, in addition to the normal writing
|
||||||
* to a file
|
* to a file
|
||||||
*/
|
*/
|
||||||
public void testSaveToOutputStream() throws Exception {
|
@Test
|
||||||
|
public void saveToOutputStream() throws Exception {
|
||||||
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
||||||
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageOpenSaveTMP.docx");
|
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageOpenSaveTMP.docx");
|
||||||
|
|
||||||
@ -334,7 +359,8 @@ public final class TestPackage extends TestCase {
|
|||||||
* simple InputStream, in addition to the normal
|
* simple InputStream, in addition to the normal
|
||||||
* reading from a file
|
* reading from a file
|
||||||
*/
|
*/
|
||||||
public void testOpenFromInputStream() throws Exception {
|
@Test
|
||||||
|
public void openFromInputStream() throws Exception {
|
||||||
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
||||||
|
|
||||||
FileInputStream finp = new FileInputStream(originalFile);
|
FileInputStream finp = new FileInputStream(originalFile);
|
||||||
@ -353,7 +379,9 @@ public final class TestPackage extends TestCase {
|
|||||||
/**
|
/**
|
||||||
* TODO: fix and enable
|
* TODO: fix and enable
|
||||||
*/
|
*/
|
||||||
public void disabled_testRemovePartRecursive() throws Exception {
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void removePartRecursive() throws Exception {
|
||||||
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
String originalFile = OpenXML4JTestDataSamples.getSampleFileName("TestPackageCommon.docx");
|
||||||
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageRemovePartRecursiveOUTPUT.docx");
|
File targetFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageRemovePartRecursiveOUTPUT.docx");
|
||||||
File tempFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageRemovePartRecursiveTMP.docx");
|
File tempFile = OpenXML4JTestDataSamples.getOutputFile("TestPackageRemovePartRecursiveTMP.docx");
|
||||||
@ -369,7 +397,8 @@ public final class TestPackage extends TestCase {
|
|||||||
assertTrue(targetFile.delete());
|
assertTrue(targetFile.delete());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDeletePart() throws InvalidFormatException {
|
@Test
|
||||||
|
public void deletePart() throws InvalidFormatException {
|
||||||
TreeMap<PackagePartName, String> expectedValues;
|
TreeMap<PackagePartName, String> expectedValues;
|
||||||
TreeMap<PackagePartName, String> values;
|
TreeMap<PackagePartName, String> values;
|
||||||
|
|
||||||
@ -426,7 +455,8 @@ public final class TestPackage extends TestCase {
|
|||||||
p.revert();
|
p.revert();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDeletePartRecursive() throws InvalidFormatException {
|
@Test
|
||||||
|
public void deletePartRecursive() throws InvalidFormatException {
|
||||||
TreeMap<PackagePartName, String> expectedValues;
|
TreeMap<PackagePartName, String> expectedValues;
|
||||||
TreeMap<PackagePartName, String> values;
|
TreeMap<PackagePartName, String> values;
|
||||||
|
|
||||||
@ -468,7 +498,8 @@ public final class TestPackage extends TestCase {
|
|||||||
* Test that we can open a file by path, and then
|
* Test that we can open a file by path, and then
|
||||||
* write changes to it.
|
* write changes to it.
|
||||||
*/
|
*/
|
||||||
public void testOpenFileThenOverwrite() throws Exception {
|
@Test
|
||||||
|
public void openFileThenOverwrite() throws Exception {
|
||||||
File tempFile = TempFile.createTempFile("poiTesting","tmp");
|
File tempFile = TempFile.createTempFile("poiTesting","tmp");
|
||||||
File origFile = OpenXML4JTestDataSamples.getSampleFile("TestPackageCommon.docx");
|
File origFile = OpenXML4JTestDataSamples.getSampleFile("TestPackageCommon.docx");
|
||||||
FileHelper.copyFile(origFile, tempFile);
|
FileHelper.copyFile(origFile, tempFile);
|
||||||
@ -505,7 +536,8 @@ public final class TestPackage extends TestCase {
|
|||||||
* Test that we can open a file by path, save it
|
* Test that we can open a file by path, save it
|
||||||
* to another file, then delete both
|
* to another file, then delete both
|
||||||
*/
|
*/
|
||||||
public void testOpenFileThenSaveDelete() throws Exception {
|
@Test
|
||||||
|
public void openFileThenSaveDelete() throws Exception {
|
||||||
File tempFile = TempFile.createTempFile("poiTesting","tmp");
|
File tempFile = TempFile.createTempFile("poiTesting","tmp");
|
||||||
File tempFile2 = TempFile.createTempFile("poiTesting","tmp");
|
File tempFile2 = TempFile.createTempFile("poiTesting","tmp");
|
||||||
File origFile = OpenXML4JTestDataSamples.getSampleFile("TestPackageCommon.docx");
|
File origFile = OpenXML4JTestDataSamples.getSampleFile("TestPackageCommon.docx");
|
||||||
@ -529,7 +561,8 @@ public final class TestPackage extends TestCase {
|
|||||||
return (ContentTypeManager)f.get(pkg);
|
return (ContentTypeManager)f.get(pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetPartsByName() throws Exception {
|
@Test
|
||||||
|
public void getPartsByName() throws Exception {
|
||||||
String filepath = OpenXML4JTestDataSamples.getSampleFileName("sample.docx");
|
String filepath = OpenXML4JTestDataSamples.getSampleFileName("sample.docx");
|
||||||
|
|
||||||
OPCPackage pkg = OPCPackage.open(filepath, PackageAccess.READ_WRITE);
|
OPCPackage pkg = OPCPackage.open(filepath, PackageAccess.READ_WRITE);
|
||||||
@ -553,7 +586,8 @@ public final class TestPackage extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetPartSize() throws Exception {
|
@Test
|
||||||
|
public void getPartSize() throws Exception {
|
||||||
String filepath = OpenXML4JTestDataSamples.getSampleFileName("sample.docx");
|
String filepath = OpenXML4JTestDataSamples.getSampleFileName("sample.docx");
|
||||||
OPCPackage pkg = OPCPackage.open(filepath, PackageAccess.READ);
|
OPCPackage pkg = OPCPackage.open(filepath, PackageAccess.READ);
|
||||||
try {
|
try {
|
||||||
@ -585,7 +619,8 @@ public final class TestPackage extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReplaceContentType() throws Exception {
|
@Test
|
||||||
|
public void replaceContentType() throws Exception {
|
||||||
InputStream is = OpenXML4JTestDataSamples.openSampleStream("sample.xlsx");
|
InputStream is = OpenXML4JTestDataSamples.openSampleStream("sample.xlsx");
|
||||||
OPCPackage p = OPCPackage.open(is);
|
OPCPackage p = OPCPackage.open(is);
|
||||||
|
|
||||||
@ -603,4 +638,113 @@ public final class TestPackage extends TestCase {
|
|||||||
assertFalse(mgr.isContentTypeRegister("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"));
|
assertFalse(mgr.isContentTypeRegister("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"));
|
||||||
assertTrue(mgr.isContentTypeRegister("application/vnd.ms-excel.sheet.macroEnabled.main+xml"));
|
assertTrue(mgr.isContentTypeRegister("application/vnd.ms-excel.sheet.macroEnabled.main+xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=IOException.class)
|
||||||
|
public void zipBombCreateAndHandle() throws Exception {
|
||||||
|
// #50090 / #56865
|
||||||
|
ZipFile zipFile = ZipHelper.openZipFile(OpenXML4JTestDataSamples.getSampleFile("sample.xlsx"));
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ZipOutputStream append = new ZipOutputStream(bos);
|
||||||
|
// first, copy contents from existing war
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry e2 = entries.nextElement();
|
||||||
|
ZipEntry e = new ZipEntry(e2.getName());
|
||||||
|
e.setTime(e2.getTime());
|
||||||
|
e.setComment(e2.getComment());
|
||||||
|
e.setSize(e2.getSize());
|
||||||
|
|
||||||
|
append.putNextEntry(e);
|
||||||
|
if (!e.isDirectory()) {
|
||||||
|
InputStream is = zipFile.getInputStream(e);
|
||||||
|
if (e.getName().equals("[Content_Types].xml")) {
|
||||||
|
ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
|
||||||
|
IOUtils.copy(is, bos2);
|
||||||
|
long size = bos2.size()-"</Types>".length();
|
||||||
|
append.write(bos2.toByteArray(), 0, (int)size);
|
||||||
|
byte spam[] = new byte[0x7FFF];
|
||||||
|
for (int i=0; i<spam.length; i++) spam[i] = ' ';
|
||||||
|
while (size < 0x7FFF0000) {
|
||||||
|
append.write(spam);
|
||||||
|
size += spam.length;
|
||||||
|
}
|
||||||
|
append.write("</Types>".getBytes());
|
||||||
|
size += 8;
|
||||||
|
e.setSize(size);
|
||||||
|
} else {
|
||||||
|
IOUtils.copy(is, append);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
append.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
append.close();
|
||||||
|
zipFile.close();
|
||||||
|
|
||||||
|
byte buf[] = bos.toByteArray();
|
||||||
|
bos = null;
|
||||||
|
|
||||||
|
Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(buf));
|
||||||
|
wb.getSheetAt(0);
|
||||||
|
wb.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void zipBombCheckSizes() throws Exception {
|
||||||
|
File file = OpenXML4JTestDataSamples.getSampleFile("sample.xlsx");
|
||||||
|
|
||||||
|
try {
|
||||||
|
double min_ratio = Double.MAX_VALUE;
|
||||||
|
long max_size = 0;
|
||||||
|
ZipFile zf = ZipHelper.openZipFile(file);
|
||||||
|
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry ze = entries.nextElement();
|
||||||
|
double ratio = (double)ze.getCompressedSize() / (double)ze.getSize();
|
||||||
|
min_ratio = Math.min(min_ratio, ratio);
|
||||||
|
max_size = Math.max(max_size, ze.getSize());
|
||||||
|
}
|
||||||
|
zf.close();
|
||||||
|
|
||||||
|
// use values close to, but within the limits
|
||||||
|
ZipSecureFile.setMinInflateRatio(min_ratio-0.002);
|
||||||
|
ZipSecureFile.setMaxEntrySize(max_size+1);
|
||||||
|
Workbook wb = WorkbookFactory.create(file);
|
||||||
|
wb.close();
|
||||||
|
|
||||||
|
// check ratio ouf of bounds
|
||||||
|
ZipSecureFile.setMinInflateRatio(min_ratio+0.002);
|
||||||
|
try {
|
||||||
|
wb = WorkbookFactory.create(file);
|
||||||
|
wb.close();
|
||||||
|
// this is a bit strange, as there will be different exceptions thrown
|
||||||
|
// depending if this executed via "ant test" or within eclipse
|
||||||
|
// maybe a difference in JDK ...
|
||||||
|
} catch (InvalidFormatException e) {
|
||||||
|
assertEquals("Zip bomb detected! Exiting.", e.getMessage());
|
||||||
|
} catch (POIXMLException e) {
|
||||||
|
InvocationTargetException t = (InvocationTargetException)e.getCause();
|
||||||
|
IOException t2 = (IOException)t.getTargetException();
|
||||||
|
assertEquals("Zip bomb detected! Exiting.", t2.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// check max entry size ouf of bounds
|
||||||
|
ZipSecureFile.setMinInflateRatio(min_ratio-0.002);
|
||||||
|
ZipSecureFile.setMaxEntrySize(max_size-1);
|
||||||
|
try {
|
||||||
|
wb = WorkbookFactory.create(file, null, true);
|
||||||
|
wb.close();
|
||||||
|
} catch (InvalidFormatException e) {
|
||||||
|
assertEquals("Zip bomb detected! Exiting.", e.getMessage());
|
||||||
|
} catch (POIXMLException e) {
|
||||||
|
InvocationTargetException t = (InvocationTargetException)e.getCause();
|
||||||
|
IOException t2 = (IOException)t.getTargetException();
|
||||||
|
assertEquals("Zip bomb detected! Exiting.", t2.getMessage());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// reset otherwise a lot of ooxml tests will fail
|
||||||
|
ZipSecureFile.setMinInflateRatio(0.01d);
|
||||||
|
ZipSecureFile.setMaxEntrySize(0xFFFFFFFFl);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,6 +516,7 @@ public final class ExcelFileFormatDocFunctionExtractor {
|
|||||||
ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )");
|
ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )");
|
||||||
ps.println("");
|
ps.println("");
|
||||||
try {
|
try {
|
||||||
|
// can't use ZipHelper here, because its in a different module
|
||||||
ZipFile zf = new ZipFile(effDocFile);
|
ZipFile zf = new ZipFile(effDocFile);
|
||||||
InputStream is = zf.getInputStream(zf.getEntry("content.xml"));
|
InputStream is = zf.getInputStream(zf.getEntry("content.xml"));
|
||||||
extractFunctionData(new FunctionDataCollector(ps), is);
|
extractFunctionData(new FunctionDataCollector(ps), is);
|
||||||
|
Loading…
Reference in New Issue
Block a user