| /* ==================================================================== |
| 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 static org.apache.poi.extractor.ExtractorFactory.OOXML_PACKAGE; |
| |
| import java.io.FilterInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.security.GeneralSecurityException; |
| |
| import org.apache.poi.EncryptedDocumentException; |
| import org.apache.poi.poifs.crypt.Decryptor; |
| import org.apache.poi.poifs.crypt.EncryptionInfo; |
| import org.apache.poi.util.Internal; |
| import org.apache.poi.util.Removal; |
| |
| /** |
| * A small base class for the various factories, e.g. WorkbookFactory, |
| * SlideShowFactory to combine common code here. |
| */ |
| @Internal |
| public final class DocumentFactoryHelper { |
| private DocumentFactoryHelper() { |
| } |
| |
| /** |
| * Wrap the OLE2 data in the {@link POIFSFileSystem} 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 POIFSFileSystem fs, String password) |
| throws IOException { |
| // wrap the stream in a FilterInputStream to close the POIFSFileSystem |
| // as well when the resulting OPCPackage is closed |
| return new FilterInputStream(getDecryptedStream(fs.getRoot(), password)) { |
| @Override |
| public void close() throws IOException { |
| fs.close(); |
| super.close(); |
| } |
| }; |
| } |
| |
| /** |
| * Wrap the OLE2 data of the DirectoryNode into a decrypted stream by using |
| * the given password. |
| * |
| * @param root The OLE2 directory node 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 DirectoryNode root, String password) |
| throws IOException { |
| // first check if the node contains an plain package |
| if (root.hasEntry(OOXML_PACKAGE)) { |
| return root.createDocumentInputStream(OOXML_PACKAGE); |
| } |
| |
| EncryptionInfo info = new EncryptionInfo(root); |
| 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) { |
| return d.getDataStream(root); |
| } 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) has a OOXML (zip) header at the start of it.<p> |
| * |
| * If unsure if your InputStream does support mark / reset, |
| * use {@link FileMagic#prepareToCheckMagic(InputStream)} to wrap it and make |
| * sure to always use that, and not the original! |
| * |
| * @param inp An InputStream which supports either mark/reset |
| * |
| * @deprecated in 3.17-beta2, use {@link FileMagic#valueOf(InputStream)} == FileMagic.OOXML instead |
| */ |
| @Deprecated |
| @Removal(version="4.0") |
| public static boolean hasOOXMLHeader(InputStream inp) throws IOException { |
| return FileMagic.valueOf(inp) == FileMagic.OOXML; |
| } |
| } |