Author: centic
Date: Sat Mar 12 11:37:32 2016
New Revision: 1734691
URL: http://svn.apache.org/viewvc?rev=1734691&view=rev
Log:
Refactor some common code from the various Document-Factories into a helper
class
Fix a potential file-handle-leak for password protected workbooks or slideshows
Added:
poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentFactoryHelper.java
Modified:
poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java
poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocument.java
poi/trunk/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java
poi/trunk/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
poi/trunk/src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java
Added:
poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentFactoryHelper.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentFactoryHelper.java?rev=1734691&view=auto
==============================================================================
---
poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentFactoryHelper.java
(added)
+++
poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentFactoryHelper.java
Sat Mar 12 11:37:32 2016
@@ -0,0 +1,116 @@
+/* ====================================================================
+ 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.poifs.filesystem;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.util.IOUtils;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.GeneralSecurityException;
+
+/**
+ * A small base class for the various factories, e.g. WorkbookFactory,
+ * SlideShowFactory to combine common code here.
+ */
+public class DocumentFactoryHelper {
+ /**
+ * Wrap the OLE2 data in the NPOIFSFileSystem into a decrypted stream by
using
+ * the given password.
+ *
+ * @param fs The OLE2 stream for the document
+ * @param password The password, null if the default password should be
used
+ * @return A stream for reading the decrypted data
+ * @throws IOException If an error occurs while decrypting or if the
password does not match
+ */
+ public static InputStream getDecryptedStream(final NPOIFSFileSystem fs,
String password)
+ throws IOException {
+ EncryptionInfo info = new EncryptionInfo(fs);
+ Decryptor d = Decryptor.getInstance(info);
+
+ try {
+ boolean passwordCorrect = false;
+ if (password != null && d.verifyPassword(password)) {
+ passwordCorrect = true;
+ }
+ if (!passwordCorrect &&
d.verifyPassword(Decryptor.DEFAULT_PASSWORD)) {
+ passwordCorrect = true;
+ }
+
+ if (passwordCorrect) {
+ // wrap the stream in a FilterInputStream to close the
NPOIFSFileSystem
+ // as well when the resulting OPCPackage is closed
+ return new FilterInputStream(d.getDataStream(fs.getRoot())) {
+ @Override
+ public void close() throws IOException {
+ fs.close();
+
+ super.close();
+ }
+ };
+ } else {
+ if (password != null)
+ throw new EncryptedDocumentException("Password incorrect");
+ else
+ throw new EncryptedDocumentException("The supplied
spreadsheet is protected, but no password was supplied");
+ }
+ } catch (GeneralSecurityException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
+ * Checks that the supplied InputStream (which MUST
+ * support mark and reset, or be a PushbackInputStream)
+ * has a OOXML (zip) header at the start of it.
+ * If your InputStream does not support mark / reset,
+ * then wrap it in a PushBackInputStream, then be
+ * sure to always use that, and not the original!
+ * @param inp An InputStream which supports either mark/reset, or is a
PushbackInputStream
+ */
+ public static boolean hasOOXMLHeader(InputStream inp) throws IOException {
+ // We want to peek at the first 4 bytes
+ inp.mark(4);
+
+ byte[] header = new byte[4];
+ int bytesRead = IOUtils.readFully(inp, header);
+
+ // Wind back those 4 bytes
+ if(inp instanceof PushbackInputStream) {
+ PushbackInputStream pin = (PushbackInputStream)inp;
+ pin.unread(header, 0, bytesRead);
+ } else {
+ inp.reset();
+ }
+
+ // Did it match the ooxml zip signature?
+ return (
+ bytesRead == 4 &&
+ header[0] == POIFSConstants.OOXML_FILE_HEADER[0] &&
+ header[1] == POIFSConstants.OOXML_FILE_HEADER[1] &&
+ header[2] == POIFSConstants.OOXML_FILE_HEADER[2] &&
+ header[3] == POIFSConstants.OOXML_FILE_HEADER[3]
+ );
+ }
+
+}
Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java?rev=1734691&r1=1734690&r2=1734691&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java
(original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShowFactory.java Sat
Mar 12 11:37:32 2016
@@ -16,29 +16,21 @@
==================================================================== */
package org.apache.poi.sl.usermodel;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
+import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.security.GeneralSecurityException;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.OldFileFormatException;
+import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.poifs.crypt.Decryptor;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.util.IOUtils;
public class SlideShowFactory {
- /** The first 4 bytes of an OOXML file, used in detection */
- private static final byte[] OOXML_FILE_HEADER = { 0x50, 0x4b, 0x03, 0x04 };
-
/**
* Creates a SlideShow from the given NPOIFSFileSystem.
*
@@ -63,37 +55,16 @@ public class SlideShowFactory {
*
* @throws IOException if an error occurs while reading the data
*/
- public static SlideShow<?,?> create(NPOIFSFileSystem fs, String password)
throws IOException {
+ public static SlideShow<?,?> create(final NPOIFSFileSystem fs, String
password) throws IOException {
DirectoryNode root = fs.getRoot();
// Encrypted OOXML files go inside OLE2 containers, is this one?
if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
- EncryptionInfo info = new EncryptionInfo(fs);
- Decryptor d = Decryptor.getInstance(info);
-
- boolean passwordCorrect = false;
InputStream stream = null;
try {
- if (password != null && d.verifyPassword(password)) {
- passwordCorrect = true;
- }
- if (!passwordCorrect &&
d.verifyPassword(Decryptor.DEFAULT_PASSWORD)) {
- passwordCorrect = true;
- }
- if (passwordCorrect) {
- stream = d.getDataStream(root);
- }
-
- if (!passwordCorrect) {
- String err = (password != null)
- ? "Password incorrect"
- : "The supplied spreadsheet is protected, but no
password was supplied";
- throw new EncryptedDocumentException(err);
- }
+ stream = DocumentFactoryHelper.getDecryptedStream(fs,
password);
return createXSLFSlideShow(stream);
- } catch (GeneralSecurityException e) {
- throw new IOException(e);
} finally {
if (stream != null) stream.close();
}
@@ -171,7 +142,7 @@ public class SlideShowFactory {
NPOIFSFileSystem fs = new NPOIFSFileSystem(inp);
return create(fs, password);
}
- if (hasOOXMLHeader(inp)) {
+ if (DocumentFactoryHelper.hasOOXMLHeader(inp)) {
return createXSLFSlideShow(inp);
}
throw new IllegalArgumentException("Your InputStream was neither an
OLE2 stream, nor an OOXML stream");
@@ -291,35 +262,4 @@ public class SlideShowFactory {
throw new IOException(e);
}
}
-
- /**
- * This copied over from ooxml, because we can't rely on these classes in
the main package
- *
- * @see org.apache.poi.POIXMLDocument#hasOOXMLHeader(InputStream)
- */
- protected static boolean hasOOXMLHeader(InputStream inp) throws
IOException {
- // We want to peek at the first 4 bytes
- inp.mark(4);
-
- byte[] header = new byte[4];
- int bytesRead = IOUtils.readFully(inp, header);
-
- // Wind back those 4 bytes
- if(inp instanceof PushbackInputStream) {
- PushbackInputStream pin = (PushbackInputStream)inp;
- pin.unread(header, 0, bytesRead);
- } else {
- inp.reset();
- }
-
- // Did it match the ooxml zip signature?
- return (
- bytesRead == 4 &&
- header[0] == OOXML_FILE_HEADER[0] &&
- header[1] == OOXML_FILE_HEADER[1] &&
- header[2] == OOXML_FILE_HEADER[2] &&
- header[3] == OOXML_FILE_HEADER[3]
- );
- }
-
}
Modified: poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocument.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocument.java?rev=1734691&r1=1734690&r2=1734691&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocument.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocument.java Sat Mar 12
11:37:32 2016
@@ -36,6 +36,7 @@ import org.apache.poi.openxml4j.opc.Pack
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.util.IOUtils;
import org.apache.xmlbeans.impl.common.SystemCache;
@@ -122,30 +123,11 @@ public abstract class POIXMLDocument ext
* then wrap it in a PushBackInputStream, then be
* sure to always use that, and not the original!
* @param inp An InputStream which supports either mark/reset, or is a
PushbackInputStream
+ *
+ * @deprecated use the method from DocumentFactoryHelper, deprecated as of
3.15-beta1, therefore eligible for removal in 3.17
*/
public static boolean hasOOXMLHeader(InputStream inp) throws IOException {
- // We want to peek at the first 4 bytes
- inp.mark(4);
-
- byte[] header = new byte[4];
- int bytesRead = IOUtils.readFully(inp, header);
-
- // Wind back those 4 bytes
- if(inp instanceof PushbackInputStream) {
- PushbackInputStream pin = (PushbackInputStream)inp;
- pin.unread(header, 0, bytesRead);
- } else {
- inp.reset();
- }
-
- // Did it match the ooxml zip signature?
- return (
- bytesRead == 4 &&
- header[0] == POIFSConstants.OOXML_FILE_HEADER[0] &&
- header[1] == POIFSConstants.OOXML_FILE_HEADER[1] &&
- header[2] == POIFSConstants.OOXML_FILE_HEADER[2] &&
- header[3] == POIFSConstants.OOXML_FILE_HEADER[3]
- );
+ return DocumentFactoryHelper.hasOOXMLHeader(inp);
}
/**
Modified:
poi/trunk/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java?rev=1734691&r1=1734690&r2=1734691&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java Sat
Mar 12 11:37:32 2016
@@ -51,14 +51,7 @@ import org.apache.poi.openxml4j.opc.Pack
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
-import org.apache.poi.poifs.filesystem.DirectoryEntry;
-import org.apache.poi.poifs.filesystem.DirectoryNode;
-import org.apache.poi.poifs.filesystem.Entry;
-import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
-import org.apache.poi.poifs.filesystem.NotOLE2FileException;
-import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
-import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.xdgf.extractor.XDGFVisioExtractor;
import org.apache.poi.xslf.extractor.XSLFPowerPointExtractor;
import org.apache.poi.xslf.usermodel.XSLFRelation;
@@ -190,7 +183,7 @@ public class ExtractorFactory {
if(NPOIFSFileSystem.hasPOIFSHeader(inp)) {
return createExtractor(new NPOIFSFileSystem(inp));
}
- if(POIXMLDocument.hasOOXMLHeader(inp)) {
+ if(DocumentFactoryHelper.hasOOXMLHeader(inp)) {
return createExtractor(OPCPackage.open(inp));
}
throw new IllegalArgumentException("Your InputStream was
neither an OLE2 stream, nor an OOXML stream");
Modified:
poi/trunk/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java?rev=1734691&r1=1734690&r2=1734691&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/ss/usermodel/WorkbookFactory.java
Sat Mar 12 11:37:32 2016
@@ -17,18 +17,16 @@
package org.apache.poi.ss.usermodel;
import java.io.*;
-import java.security.GeneralSecurityException;
import org.apache.poi.EmptyFileException;
import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.POIXMLDocument;
+import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.Decryptor;
-import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
@@ -82,40 +80,7 @@ public class WorkbookFactory {
// Encrypted OOXML files go inside OLE2 containers, is this one?
if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
- EncryptionInfo info = new EncryptionInfo(fs);
- Decryptor d = Decryptor.getInstance(info);
-
- boolean passwordCorrect = false;
- InputStream stream = null;
- try {
- if (password != null && d.verifyPassword(password)) {
- passwordCorrect = true;
- }
- if (!passwordCorrect &&
d.verifyPassword(Decryptor.DEFAULT_PASSWORD)) {
- passwordCorrect = true;
- }
- if (passwordCorrect) {
- // wrap the stream in a FilterInputStream to close the
NPOIFSFileSystem
- // as well when the resulting OPCPackage is closed
- stream = new FilterInputStream(d.getDataStream(root)) {
- @Override
- public void close() throws IOException {
- fs.close();
-
- super.close();
- }
- };
- }
- } catch (GeneralSecurityException e) {
- throw new IOException(e);
- }
-
- if (! passwordCorrect) {
- if (password != null)
- throw new EncryptedDocumentException("Password incorrect");
- else
- throw new EncryptedDocumentException("The supplied
spreadsheet is protected, but no password was supplied");
- }
+ InputStream stream = DocumentFactoryHelper.getDecryptedStream(fs,
password);
OPCPackage pkg = OPCPackage.open(stream);
return create(pkg);
@@ -212,7 +177,7 @@ public class WorkbookFactory {
NPOIFSFileSystem fs = new NPOIFSFileSystem(inp);
return create(fs, password);
}
- if (POIXMLDocument.hasOOXMLHeader(inp)) {
+ if (DocumentFactoryHelper.hasOOXMLHeader(inp)) {
return new XSSFWorkbook(OPCPackage.open(inp));
}
throw new InvalidFormatException("Your InputStream was neither an OLE2
stream, nor an OOXML stream");
Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java
URL:
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java?rev=1734691&r1=1734690&r2=1734691&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java
(original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/TestDetectAsOOXML.java Sat Mar
12 11:37:32 2016
@@ -28,6 +28,7 @@ import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
/**
* Class to test that HXF correctly detects OOXML
@@ -47,21 +48,21 @@ public class TestDetectAsOOXML extends T
in = new PushbackInputStream(
HSSFTestDataSamples.openSampleFileStream("SampleSS.xlsx"), 10
);
- assertTrue(POIXMLDocument.hasOOXMLHeader(in));
+ assertTrue(DocumentFactoryHelper.hasOOXMLHeader(in));
in.close();
// xls file isn't
in = new PushbackInputStream(
HSSFTestDataSamples.openSampleFileStream("SampleSS.xls"), 10
);
- assertFalse(POIXMLDocument.hasOOXMLHeader(in));
+ assertFalse(DocumentFactoryHelper.hasOOXMLHeader(in));
in.close();
// text file isn't
in = new PushbackInputStream(
HSSFTestDataSamples.openSampleFileStream("SampleSS.txt"), 10
);
- assertFalse(POIXMLDocument.hasOOXMLHeader(in));
+ assertFalse(DocumentFactoryHelper.hasOOXMLHeader(in));
in.close();
}
@@ -73,13 +74,14 @@ public class TestDetectAsOOXML extends T
// detect header
InputStream in = new PushbackInputStream(testInput, 10);
- assertFalse(POIXMLDocument.hasOOXMLHeader(in));
+ assertFalse(DocumentFactoryHelper.hasOOXMLHeader(in));
+ //noinspection deprecation
+ assertFalse(POIXMLDocument.hasOOXMLHeader(in));
// check if InputStream is still intact
byte[] test = new byte[3];
- in.read(test);
+ assertEquals(3, in.read(test));
assertTrue(Arrays.equals(testData, test));
assertEquals(-1, in.read());
}
-
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]