#59893 - Forbid calls to InputStream.available
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1830400 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2574fd2d3d
commit
e0f7014503
@ -17,15 +17,17 @@
|
||||
|
||||
package org.apache.poi.poifs.poibrowser;
|
||||
|
||||
import java.io.*;
|
||||
import org.apache.poi.poifs.filesystem.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||
import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
|
||||
/**
|
||||
* <p>Describes the most important (whatever that is) features of a
|
||||
* {@link POIFSDocumentPath}.</p>
|
||||
*/
|
||||
public class DocumentDescriptor
|
||||
class DocumentDescriptor
|
||||
{
|
||||
|
||||
//arbitrarily selected; may need to increase
|
||||
@ -54,26 +56,20 @@ public class DocumentDescriptor
|
||||
public DocumentDescriptor(final String name,
|
||||
final POIFSDocumentPath path,
|
||||
final DocumentInputStream stream,
|
||||
final int nrOfBytes)
|
||||
{
|
||||
final int nrOfBytes) {
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.stream = stream;
|
||||
try
|
||||
{
|
||||
size = stream.available();
|
||||
if (stream.markSupported())
|
||||
{
|
||||
try {
|
||||
if (stream.markSupported()) {
|
||||
stream.mark(nrOfBytes);
|
||||
final byte[] b = IOUtils.safelyAllocate(nrOfBytes, MAX_RECORD_LENGTH);
|
||||
final int read = stream.read(b, 0, Math.min(size, b.length));
|
||||
bytes = new byte[read];
|
||||
System.arraycopy(b, 0, bytes, 0, read);
|
||||
bytes = IOUtils.toByteArray(stream, nrOfBytes, MAX_RECORD_LENGTH);
|
||||
stream.reset();
|
||||
} else {
|
||||
bytes = new byte[0];
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
size = bytes.length + stream.available();
|
||||
} catch (IOException ex) {
|
||||
System.out.println(ex);
|
||||
}
|
||||
}
|
||||
|
@ -175,10 +175,12 @@ public class VariantSupport extends Variant {
|
||||
try {
|
||||
typedPropertyValue.readValue(lei);
|
||||
} catch ( UnsupportedOperationException exc ) {
|
||||
int propLength = Math.min( length, lei.available() );
|
||||
final byte[] v = IOUtils.safelyAllocate(propLength, MAX_RECORD_LENGTH);
|
||||
lei.readFully(v, 0, propLength);
|
||||
throw new ReadingNotSupportedException( type, v );
|
||||
try {
|
||||
final byte[] v = IOUtils.toByteArray(lei, length, MAX_RECORD_LENGTH);
|
||||
throw new ReadingNotSupportedException( type, v );
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
switch ( (int) type ) {
|
||||
|
@ -17,14 +17,13 @@
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.LittleEndianByteArrayInputStream;
|
||||
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
|
||||
import org.apache.poi.util.LittleEndianInputStream;
|
||||
import org.apache.poi.util.RecordFormatException;
|
||||
|
||||
/**
|
||||
@ -85,8 +84,7 @@ public final class ObjRecord extends Record implements Cloneable {
|
||||
*/
|
||||
|
||||
subrecords = new ArrayList<>();
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(subRecordData);
|
||||
LittleEndianInputStream subRecStream = new LittleEndianInputStream(bais);
|
||||
LittleEndianByteArrayInputStream subRecStream = new LittleEndianByteArrayInputStream(subRecordData);
|
||||
CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord)SubRecord.createSubRecord(subRecStream, 0);
|
||||
subrecords.add(cmo);
|
||||
while (true) {
|
||||
@ -96,7 +94,7 @@ public final class ObjRecord extends Record implements Cloneable {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int nRemainingBytes = bais.available();
|
||||
final int nRemainingBytes = subRecordData.length-subRecStream.getReadIndex();
|
||||
if (nRemainingBytes > 0) {
|
||||
// At present (Oct-2008), most unit test samples have (subRecordData.length % 2 == 0)
|
||||
_isPaddedToQuadByteMultiple = subRecordData.length % MAX_PAD_ALIGNMENT == 0;
|
||||
|
@ -32,6 +32,7 @@ import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.LittleEndianConsts;
|
||||
import org.apache.poi.util.LittleEndianInput;
|
||||
import org.apache.poi.util.RecordFormatException;
|
||||
import org.apache.poi.util.SuppressForbidden;
|
||||
|
||||
public final class Biff8DecryptingStream implements BiffHeaderInput, LittleEndianInput {
|
||||
|
||||
@ -39,7 +40,6 @@ public final class Biff8DecryptingStream implements BiffHeaderInput, LittleEndia
|
||||
//arbitrarily selected; may need to increase
|
||||
private static final int MAX_RECORD_LENGTH = 100_000;
|
||||
|
||||
private final EncryptionInfo info;
|
||||
private ChunkedCipherInputStream ccis;
|
||||
private final byte buffer[] = new byte[LittleEndianConsts.LONG_SIZE];
|
||||
private boolean shouldSkipEncryptionOnCurrentRecord;
|
||||
@ -55,8 +55,7 @@ public final class Biff8DecryptingStream implements BiffHeaderInput, LittleEndia
|
||||
((PushbackInputStream)stream).unread(initialBuf);
|
||||
}
|
||||
|
||||
this.info = info;
|
||||
Decryptor dec = this.info.getDecryptor();
|
||||
Decryptor dec = info.getDecryptor();
|
||||
dec.setChunkSize(RC4_REKEYING_INTERVAL);
|
||||
ccis = (ChunkedCipherInputStream)dec.getDataStream(stream, Integer.MAX_VALUE, 0);
|
||||
|
||||
@ -69,6 +68,7 @@ public final class Biff8DecryptingStream implements BiffHeaderInput, LittleEndia
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressForbidden("just delegating")
|
||||
public int available() {
|
||||
return ccis.available();
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
|
||||
private int read(byte[] b, int off, int len, boolean readPlain) throws IOException {
|
||||
int total = 0;
|
||||
|
||||
if (available() <= 0) {
|
||||
if (remainingBytes() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
|
||||
}
|
||||
}
|
||||
int count = (int)(chunk.length - (pos & chunkMask));
|
||||
int avail = available();
|
||||
int avail = remainingBytes();
|
||||
if (avail == 0) {
|
||||
return total;
|
||||
}
|
||||
@ -133,7 +133,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(final long n) throws IOException {
|
||||
public long skip(final long n) {
|
||||
long start = pos;
|
||||
long skip = Math.min(remainingBytes(), n);
|
||||
|
||||
@ -169,7 +169,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
public synchronized void reset() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
|
||||
}
|
||||
|
||||
final int todo = (int)Math.min(size, chunk.length);
|
||||
int readBytes = 0, totalBytes = 0;
|
||||
int readBytes, totalBytes = 0;
|
||||
do {
|
||||
readBytes = super.read(plain, totalBytes, todo-totalBytes);
|
||||
totalBytes += Math.max(0, readBytes);
|
||||
@ -211,10 +211,6 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
|
||||
/**
|
||||
* Helper function for overriding the cipher invocation, i.e. XOR doesn't use a cipher
|
||||
* and uses it's own implementation
|
||||
*
|
||||
* @throws BadPaddingException
|
||||
* @throws IllegalBlockSizeException
|
||||
* @throws ShortBufferException
|
||||
*/
|
||||
protected int invokeCipher(int totalBytes, boolean doFinal) throws GeneralSecurityException {
|
||||
if (doFinal) {
|
||||
|
@ -273,11 +273,9 @@ public class POIFSReader
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
POIFSReaderListener listener = listeners.next();
|
||||
|
||||
listener.processPOIFSReaderEvent(
|
||||
new POIFSReaderEvent(
|
||||
new DocumentInputStream(document), path,
|
||||
name));
|
||||
try (DocumentInputStream dis = new DocumentInputStream(document)) {
|
||||
listener.processPOIFSReaderEvent(new POIFSReaderEvent(dis, path, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -138,7 +138,7 @@ public final class ODocumentInputStream extends DocumentInputStream {
|
||||
if (atEOD()) {
|
||||
return EOF;
|
||||
}
|
||||
int limit = Math.min(available(), len);
|
||||
int limit = Math.min(_document_size - _current_offset, len);
|
||||
readFully(b, off, limit);
|
||||
return limit;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import java.awt.image.AffineTransformOp;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RescaleOp;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
@ -39,6 +40,7 @@ import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
@ -69,20 +71,24 @@ public class BitmapImageRenderer implements ImageRenderer {
|
||||
* @return the bufferedImage or null, if there was no image reader for this content type
|
||||
* @throws IOException thrown if there was an error while processing the image
|
||||
*/
|
||||
private static BufferedImage readImage(InputStream data, String contentType) throws IOException {
|
||||
private static BufferedImage readImage(final InputStream data, final String contentType) throws IOException {
|
||||
IOException lastException = null;
|
||||
BufferedImage img = null;
|
||||
if (data.markSupported()) {
|
||||
data.mark(data.available());
|
||||
|
||||
final ByteArrayInputStream bis;
|
||||
if (data instanceof ByteArrayInputStream) {
|
||||
bis = (ByteArrayInputStream)data;
|
||||
} else {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(0x3FFFF);
|
||||
IOUtils.copy(data, bos);
|
||||
bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
// currently don't use FileCacheImageInputStream,
|
||||
// because of the risk of filling the file handles (see #59166)
|
||||
ImageInputStream iis = new MemoryCacheImageInputStream(data);
|
||||
ImageInputStream iis = new MemoryCacheImageInputStream(bis);
|
||||
try {
|
||||
iis = new MemoryCacheImageInputStream(data);
|
||||
iis.mark();
|
||||
|
||||
Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
|
||||
while (img==null && iter.hasNext()) {
|
||||
ImageReader reader = iter.next();
|
||||
@ -90,21 +96,11 @@ public class BitmapImageRenderer implements ImageRenderer {
|
||||
// 0:default mode, 1:fallback mode
|
||||
for (int mode=0; img==null && mode<3; mode++) {
|
||||
lastException = null;
|
||||
try {
|
||||
iis.reset();
|
||||
} catch (IOException e) {
|
||||
if (data.markSupported()) {
|
||||
data.reset();
|
||||
data.mark(data.available());
|
||||
iis.close();
|
||||
iis = new MemoryCacheImageInputStream(data);
|
||||
} else {
|
||||
// can't restore the input stream, so we need to stop processing here
|
||||
lastException = e;
|
||||
break;
|
||||
}
|
||||
if (mode > 0) {
|
||||
bis.reset();
|
||||
iis.close();
|
||||
iis = new MemoryCacheImageInputStream(bis);
|
||||
}
|
||||
iis.mark();
|
||||
|
||||
try {
|
||||
|
||||
|
@ -116,21 +116,57 @@ public final class IOUtils {
|
||||
* @return A byte array with the read bytes.
|
||||
* @throws IOException If reading data fails or EOF is encountered too early for the given length.
|
||||
*/
|
||||
public static byte[] toByteArray(InputStream stream, int length) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(length == Integer.MAX_VALUE ? 4096 : length);
|
||||
public static byte[] toByteArray(InputStream stream, final int length) throws IOException {
|
||||
return toByteArray(stream, length, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads up to {@code length} bytes from the input stream, and returns the bytes read.
|
||||
*
|
||||
* @param stream The byte stream of data to read.
|
||||
* @param length The maximum length to read, use {@link Integer#MAX_VALUE} to read the stream
|
||||
* until EOF
|
||||
* @param maxLength if the input is equal to/longer than {@code maxLength} bytes,
|
||||
* then throw an {@link IOException} complaining about the length.
|
||||
* use {@link Integer#MAX_VALUE} to disable the check
|
||||
* @return A byte array with the read bytes.
|
||||
* @throws IOException If reading data fails or EOF is encountered too early for the given length.
|
||||
*/
|
||||
public static byte[] toByteArray(InputStream stream, final long length, final int maxLength) throws IOException {
|
||||
if (length < 0L || maxLength < 0L) {
|
||||
throw new RecordFormatException("Can't allocate an array of length < 0");
|
||||
}
|
||||
if (length > (long)Integer.MAX_VALUE) {
|
||||
throw new RecordFormatException("Can't allocate an array > "+Integer.MAX_VALUE);
|
||||
}
|
||||
if (BYTE_ARRAY_MAX_OVERRIDE > 0) {
|
||||
if (length > BYTE_ARRAY_MAX_OVERRIDE) {
|
||||
throwRFE(length, BYTE_ARRAY_MAX_OVERRIDE);
|
||||
}
|
||||
} else if (length > maxLength) {
|
||||
throwRFE(length, maxLength);
|
||||
}
|
||||
|
||||
final int len = Math.min((int)length, maxLength);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(len == Integer.MAX_VALUE ? 4096 : len);
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int totalBytes = 0, readBytes;
|
||||
do {
|
||||
readBytes = stream.read(buffer, 0, Math.min(buffer.length, length-totalBytes));
|
||||
readBytes = stream.read(buffer, 0, Math.min(buffer.length, len-totalBytes));
|
||||
totalBytes += Math.max(readBytes,0);
|
||||
if (readBytes > 0) {
|
||||
baos.write(buffer, 0, readBytes);
|
||||
}
|
||||
} while (totalBytes < length && readBytes > -1);
|
||||
} while (totalBytes < len && readBytes > -1);
|
||||
|
||||
if (length != Integer.MAX_VALUE && totalBytes < length) {
|
||||
throw new IOException("unexpected EOF");
|
||||
if (maxLength != Integer.MAX_VALUE && totalBytes == maxLength) {
|
||||
throw new IOException("MaxLength ("+maxLength+") reached - stream seems to be invalid.");
|
||||
}
|
||||
|
||||
if (len != Integer.MAX_VALUE && totalBytes < len) {
|
||||
throw new EOFException("unexpected EOF");
|
||||
}
|
||||
|
||||
return baos.toByteArray();
|
||||
@ -350,19 +386,19 @@ public final class IOUtils {
|
||||
*
|
||||
* @param inp The {@link InputStream} which provides the data
|
||||
* @param out The {@link OutputStream} to write the data to
|
||||
* @return the amount of bytes copied
|
||||
*
|
||||
* @throws IOException If copying the data fails.
|
||||
*/
|
||||
public static void copy(InputStream inp, OutputStream out) throws IOException {
|
||||
byte[] buff = new byte[4096];
|
||||
int count;
|
||||
while ((count = inp.read(buff)) != -1) {
|
||||
if (count < -1) {
|
||||
throw new RecordFormatException("Can't have read < -1 bytes");
|
||||
}
|
||||
public static long copy(InputStream inp, OutputStream out) throws IOException {
|
||||
final byte[] buff = new byte[4096];
|
||||
long totalCount = 0;
|
||||
for (int count; (count = inp.read(buff)) != -1; totalCount += count) {
|
||||
if (count > 0) {
|
||||
out.write(buff, 0, count);
|
||||
}
|
||||
}
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -370,16 +406,18 @@ public final class IOUtils {
|
||||
*
|
||||
* @param srcStream The {@link InputStream} which provides the data
|
||||
* @param destFile The file where the data should be stored
|
||||
* @return the amount of bytes copied
|
||||
*
|
||||
* @throws IOException If the target directory does not exist and cannot be created
|
||||
* or if copying the data fails.
|
||||
*/
|
||||
public static void copy(InputStream srcStream, File destFile) throws IOException {
|
||||
public static long copy(InputStream srcStream, File destFile) throws IOException {
|
||||
File destDirectory = destFile.getParentFile();
|
||||
if (!(destDirectory.exists() || destDirectory.mkdirs())) {
|
||||
throw new RuntimeException("Can't create destination directory: "+destDirectory);
|
||||
}
|
||||
try (OutputStream destStream = new FileOutputStream(destFile)) {
|
||||
IOUtils.copy(srcStream, destStream);
|
||||
return IOUtils.copy(srcStream, destStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ import java.util.Date;
|
||||
|
||||
import org.apache.poi.POIXMLProperties.CoreProperties;
|
||||
import org.apache.poi.openxml4j.util.Nullable;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.LocaleUtil;
|
||||
import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
@ -249,20 +250,18 @@ public final class TestPOIXMLProperties {
|
||||
|
||||
// Adding / changing
|
||||
ByteArrayInputStream imageData = new ByteArrayInputStream(new byte[1]);
|
||||
assertEquals(1, imageData.available());
|
||||
noThumbProps.setThumbnail("Testing.png", imageData);
|
||||
assertNotNull(noThumbProps.getThumbnailPart());
|
||||
assertEquals("/Testing.png", noThumbProps.getThumbnailFilename());
|
||||
assertNotNull(noThumbProps.getThumbnailImage());
|
||||
assertEquals(1, noThumbProps.getThumbnailImage().available());
|
||||
assertEquals(1, IOUtils.toByteArray(noThumbProps.getThumbnailImage()).length);
|
||||
|
||||
imageData = new ByteArrayInputStream(new byte[2]);
|
||||
assertEquals(2, imageData.available());
|
||||
noThumbProps.setThumbnail("Testing2.png", imageData);
|
||||
assertNotNull(noThumbProps.getThumbnailPart());
|
||||
assertEquals("/Testing.png", noThumbProps.getThumbnailFilename());
|
||||
assertNotNull(noThumbProps.getThumbnailImage());
|
||||
assertEquals(2, noThumbProps.getThumbnailImage().available());
|
||||
assertEquals(2, IOUtils.toByteArray(noThumbProps.getThumbnailImage()).length);
|
||||
}
|
||||
|
||||
private static String zeroPad(long i) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
==================================================================== */
|
||||
package org.apache.poi.openxml4j.util;
|
||||
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -39,8 +40,9 @@ public class TestZipSecureFile {
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
|
||||
InputStream inputStream = secureFile.getInputStream(entry);
|
||||
assertTrue(inputStream.available() > 0);
|
||||
try (InputStream inputStream = secureFile.getInputStream(entry)) {
|
||||
assertTrue(IOUtils.toByteArray(inputStream).length > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import static org.junit.Assert.fail;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
@ -39,107 +38,92 @@ import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestDecryptor {
|
||||
private static final POIDataSamples samples = POIDataSamples.getPOIFSInstance();
|
||||
|
||||
@Test
|
||||
public void passwordVerification() throws IOException, GeneralSecurityException {
|
||||
POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx"));
|
||||
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
|
||||
assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
|
||||
|
||||
fs.close();
|
||||
try (InputStream is = samples.openResourceAsStream("protect.xlsx");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is)) {
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrypt() throws IOException, GeneralSecurityException {
|
||||
POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx"));
|
||||
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
|
||||
d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
||||
|
||||
zipOk(fs.getRoot(), d);
|
||||
|
||||
fs.close();
|
||||
try (InputStream is = samples.openResourceAsStream("protect.xlsx");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is)) {
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
||||
zipOk(fs.getRoot(), d);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void agile() throws IOException, GeneralSecurityException {
|
||||
POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx"));
|
||||
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
|
||||
assertTrue(info.getVersionMajor() == 4 && info.getVersionMinor() == 4);
|
||||
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
|
||||
assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
|
||||
|
||||
zipOk(fs.getRoot(), d);
|
||||
|
||||
fs.close();
|
||||
try (InputStream is = samples.openResourceAsStream("protected_agile.docx");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is)) {
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
assertTrue(info.getVersionMajor() == 4 && info.getVersionMinor() == 4);
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
assertTrue(d.verifyPassword(Decryptor.DEFAULT_PASSWORD));
|
||||
zipOk(fs.getRoot(), d);
|
||||
}
|
||||
}
|
||||
|
||||
private void zipOk(DirectoryNode root, Decryptor d) throws IOException, GeneralSecurityException {
|
||||
ZipInputStream zin = new ZipInputStream(d.getDataStream(root));
|
||||
try (ZipInputStream zin = new ZipInputStream(d.getDataStream(root))) {
|
||||
|
||||
while (true) {
|
||||
ZipEntry entry = zin.getNextEntry();
|
||||
if (entry==null) {
|
||||
break;
|
||||
while (true) {
|
||||
ZipEntry entry = zin.getNextEntry();
|
||||
if (entry == null) {
|
||||
break;
|
||||
}
|
||||
// crc32 is checked within zip-stream
|
||||
if (entry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
assertEquals(entry.getSize() - 1, zin.skip(entry.getSize() - 1));
|
||||
byte buf[] = new byte[10];
|
||||
int readBytes = zin.read(buf);
|
||||
// zin.available() doesn't work for entries
|
||||
assertEquals("size failed for " + entry.getName(), 1, readBytes);
|
||||
}
|
||||
// crc32 is checked within zip-stream
|
||||
if (entry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
zin.skip(entry.getSize());
|
||||
byte buf[] = new byte[10];
|
||||
int readBytes = zin.read(buf);
|
||||
// zin.available() doesn't work for entries
|
||||
assertEquals("size failed for "+entry.getName(), -1, readBytes);
|
||||
}
|
||||
|
||||
zin.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dataLength() throws Exception {
|
||||
POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx"));
|
||||
try (InputStream fsIs = samples.openResourceAsStream("protected_agile.docx");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(fsIs)) {
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
||||
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
try (InputStream is = d.getDataStream(fs)) {
|
||||
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
long len = d.getLength();
|
||||
assertEquals(12810, len);
|
||||
|
||||
d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
||||
byte[] buf = new byte[(int) len];
|
||||
assertEquals(12810, is.read(buf));
|
||||
|
||||
InputStream is = d.getDataStream(fs);
|
||||
ZipInputStream zin = new ZipInputStream(new ByteArrayInputStream(buf));
|
||||
|
||||
long len = d.getLength();
|
||||
assertEquals(12810, len);
|
||||
while (true) {
|
||||
ZipEntry entry = zin.getNextEntry();
|
||||
if (entry == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] buf = new byte[(int)len];
|
||||
|
||||
is.read(buf);
|
||||
|
||||
ZipInputStream zin = new ZipInputStream(new ByteArrayInputStream(buf));
|
||||
|
||||
while (true) {
|
||||
ZipEntry entry = zin.getNextEntry();
|
||||
if (entry==null) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (zin.available()>0) {
|
||||
zin.skip(zin.available());
|
||||
IOUtils.toByteArray(zin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,7 +132,7 @@ public class TestDecryptor {
|
||||
public void bug57080() throws Exception {
|
||||
// the test file contains a wrong ole entry size, produced by extenxls
|
||||
// the fix limits the available size and tries to read all entries
|
||||
File f = POIDataSamples.getPOIFSInstance().getFile("extenxls_pwd123.xlsx");
|
||||
File f = samples.getFile("extenxls_pwd123.xlsx");
|
||||
|
||||
try (NPOIFSFileSystem fs = new NPOIFSFileSystem(f, true)) {
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
@ -174,14 +158,12 @@ public class TestDecryptor {
|
||||
|
||||
@Test
|
||||
public void test58616() throws IOException, GeneralSecurityException {
|
||||
FileInputStream fis = new FileInputStream(XSSFTestDataSamples.getSampleFile("58616.xlsx"));
|
||||
POIFSFileSystem pfs = new POIFSFileSystem(fis);
|
||||
EncryptionInfo info = new EncryptionInfo(pfs);
|
||||
Decryptor dec = Decryptor.getInstance(info);
|
||||
//dec.verifyPassword(null);
|
||||
dec.getDataStream(pfs);
|
||||
pfs.close();
|
||||
fis.close();
|
||||
try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("58616.xlsx");
|
||||
POIFSFileSystem pfs = new POIFSFileSystem(is)) {
|
||||
EncryptionInfo info = new EncryptionInfo(pfs);
|
||||
Decryptor dec = Decryptor.getInstance(info);
|
||||
dec.getDataStream(pfs).close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -189,19 +171,12 @@ public class TestDecryptor {
|
||||
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
|
||||
Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
|
||||
|
||||
InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is);
|
||||
is.close();
|
||||
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
|
||||
boolean b = d.verifyPassword("Test001!!");
|
||||
assertTrue(b);
|
||||
|
||||
zipOk(fs.getRoot(), d);
|
||||
|
||||
fs.close();
|
||||
try (InputStream is = samples.openResourceAsStream("60320-protected.xlsx");
|
||||
POIFSFileSystem fs = new POIFSFileSystem(is)) {
|
||||
EncryptionInfo info = new EncryptionInfo(fs);
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
assertTrue(d.verifyPassword("Test001!!"));
|
||||
zipOk(fs.getRoot(), d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,18 +36,20 @@ import javax.crypto.Cipher;
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.openxml4j.opc.ContentTypes;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackageAccess;
|
||||
import org.apache.poi.poifs.crypt.agile.AgileDecryptor;
|
||||
import org.apache.poi.poifs.crypt.agile.AgileEncryptionHeader;
|
||||
import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier;
|
||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||
import org.apache.poi.poifs.filesystem.DocumentNode;
|
||||
import org.apache.poi.poifs.filesystem.Entry;
|
||||
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.util.BoundedInputStream;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.TempFile;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
@ -59,35 +61,37 @@ public class TestEncryptor {
|
||||
// ... at least the output can be opened in Excel Viewer
|
||||
String password = "pass";
|
||||
|
||||
InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleMultiCell.xlsx");
|
||||
ByteArrayOutputStream payloadExpected = new ByteArrayOutputStream();
|
||||
IOUtils.copy(is, payloadExpected);
|
||||
is.close();
|
||||
|
||||
POIFSFileSystem fs = new POIFSFileSystem();
|
||||
EncryptionInfo ei = new EncryptionInfo(EncryptionMode.binaryRC4);
|
||||
Encryptor enc = ei.getEncryptor();
|
||||
enc.confirmPassword(password);
|
||||
|
||||
OutputStream os = enc.getDataStream(fs.getRoot());
|
||||
payloadExpected.writeTo(os);
|
||||
os.close();
|
||||
final byte[] payloadExpected;
|
||||
try (InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleMultiCell.xlsx")) {
|
||||
payloadExpected = IOUtils.toByteArray(is);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
fs.writeFilesystem(bos);
|
||||
try (POIFSFileSystem fs = new POIFSFileSystem()) {
|
||||
EncryptionInfo ei = new EncryptionInfo(EncryptionMode.binaryRC4);
|
||||
Encryptor enc = ei.getEncryptor();
|
||||
enc.confirmPassword(password);
|
||||
|
||||
fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
|
||||
ei = new EncryptionInfo(fs);
|
||||
Decryptor dec = ei.getDecryptor();
|
||||
boolean b = dec.verifyPassword(password);
|
||||
assertTrue(b);
|
||||
try (OutputStream os = enc.getDataStream(fs.getRoot())) {
|
||||
os.write(payloadExpected);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream payloadActual = new ByteArrayOutputStream();
|
||||
is = dec.getDataStream(fs.getRoot());
|
||||
IOUtils.copy(is,payloadActual);
|
||||
is.close();
|
||||
fs.writeFilesystem(bos);
|
||||
}
|
||||
|
||||
assertArrayEquals(payloadExpected.toByteArray(), payloadActual.toByteArray());
|
||||
final byte[] payloadActual;
|
||||
try (POIFSFileSystem fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
|
||||
EncryptionInfo ei = new EncryptionInfo(fs);
|
||||
Decryptor dec = ei.getDecryptor();
|
||||
boolean b = dec.verifyPassword(password);
|
||||
assertTrue(b);
|
||||
|
||||
try (InputStream is = dec.getDataStream(fs.getRoot())) {
|
||||
payloadActual = IOUtils.toByteArray(is);
|
||||
}
|
||||
}
|
||||
|
||||
assertArrayEquals(payloadExpected, payloadActual);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -97,43 +101,47 @@ public class TestEncryptor {
|
||||
|
||||
File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-pass.docx");
|
||||
String pass = "pass";
|
||||
NPOIFSFileSystem nfs = new NPOIFSFileSystem(file);
|
||||
|
||||
// Check the encryption details
|
||||
EncryptionInfo infoExpected = new EncryptionInfo(nfs);
|
||||
Decryptor decExpected = Decryptor.getInstance(infoExpected);
|
||||
boolean passed = decExpected.verifyPassword(pass);
|
||||
assertTrue("Unable to process: document is encrypted", passed);
|
||||
final byte[] payloadExpected, encPackExpected;
|
||||
final long decPackLenExpected;
|
||||
final EncryptionInfo infoExpected;
|
||||
final Decryptor decExpected;
|
||||
|
||||
// extract the payload
|
||||
InputStream is = decExpected.getDataStream(nfs);
|
||||
byte payloadExpected[] = IOUtils.toByteArray(is);
|
||||
is.close();
|
||||
try (NPOIFSFileSystem nfs = new NPOIFSFileSystem(file, true)) {
|
||||
|
||||
long decPackLenExpected = decExpected.getLength();
|
||||
assertEquals(decPackLenExpected, payloadExpected.length);
|
||||
// Check the encryption details
|
||||
infoExpected = new EncryptionInfo(nfs);
|
||||
decExpected = Decryptor.getInstance(infoExpected);
|
||||
boolean passed = decExpected.verifyPassword(pass);
|
||||
assertTrue("Unable to process: document is encrypted", passed);
|
||||
|
||||
is = nfs.getRoot().createDocumentInputStream(Decryptor.DEFAULT_POIFS_ENTRY);
|
||||
is = new BoundedInputStream(is, is.available()-16); // ignore padding block
|
||||
byte encPackExpected[] = IOUtils.toByteArray(is);
|
||||
is.close();
|
||||
// extract the payload
|
||||
try (InputStream is = decExpected.getDataStream(nfs)) {
|
||||
payloadExpected = IOUtils.toByteArray(is);
|
||||
}
|
||||
|
||||
// listDir(nfs.getRoot(), "orig", "");
|
||||
decPackLenExpected = decExpected.getLength();
|
||||
assertEquals(decPackLenExpected, payloadExpected.length);
|
||||
|
||||
nfs.close();
|
||||
final DirectoryNode root = nfs.getRoot();
|
||||
final DocumentEntry entry = (DocumentEntry)root.getEntry(Decryptor.DEFAULT_POIFS_ENTRY);
|
||||
try (InputStream is = root.createDocumentInputStream(entry)) {
|
||||
// ignore padding block
|
||||
encPackExpected = IOUtils.toByteArray(is, entry.getSize()-16);
|
||||
}
|
||||
}
|
||||
|
||||
// check that same verifier/salt lead to same hashes
|
||||
byte verifierSaltExpected[] = infoExpected.getVerifier().getSalt();
|
||||
byte verifierExpected[] = decExpected.getVerifier();
|
||||
byte keySalt[] = infoExpected.getHeader().getKeySalt();
|
||||
byte keySpec[] = decExpected.getSecretKey().getEncoded();
|
||||
byte integritySalt[] = decExpected.getIntegrityHmacKey();
|
||||
final byte verifierSaltExpected[] = infoExpected.getVerifier().getSalt();
|
||||
final byte verifierExpected[] = decExpected.getVerifier();
|
||||
final byte keySalt[] = infoExpected.getHeader().getKeySalt();
|
||||
final byte keySpec[] = decExpected.getSecretKey().getEncoded();
|
||||
final byte integritySalt[] = decExpected.getIntegrityHmacKey();
|
||||
// the hmacs of the file always differ, as we use PKCS5-padding to pad the bytes
|
||||
// whereas office just uses random bytes
|
||||
// byte integrityHash[] = d.getIntegrityHmacValue();
|
||||
|
||||
POIFSFileSystem fs = new POIFSFileSystem();
|
||||
EncryptionInfo infoActual = new EncryptionInfo(
|
||||
final EncryptionInfo infoActual = new EncryptionInfo(
|
||||
EncryptionMode.agile
|
||||
, infoExpected.getVerifier().getCipherAlgorithm()
|
||||
, infoExpected.getVerifier().getHashAlgorithm()
|
||||
@ -145,35 +153,37 @@ public class TestEncryptor {
|
||||
Encryptor e = Encryptor.getInstance(infoActual);
|
||||
e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, integritySalt);
|
||||
|
||||
OutputStream os = e.getDataStream(fs);
|
||||
IOUtils.copy(new ByteArrayInputStream(payloadExpected), os);
|
||||
os.close();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
fs.writeFilesystem(bos);
|
||||
fs.close();
|
||||
try (POIFSFileSystem fs = new POIFSFileSystem()) {
|
||||
try (OutputStream os = e.getDataStream(fs)) {
|
||||
os.write(payloadExpected);
|
||||
}
|
||||
fs.writeFilesystem(bos);
|
||||
}
|
||||
|
||||
nfs = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
|
||||
infoActual = new EncryptionInfo(nfs.getRoot());
|
||||
Decryptor decActual = Decryptor.getInstance(infoActual);
|
||||
passed = decActual.verifyPassword(pass);
|
||||
assertTrue("Unable to process: document is encrypted", passed);
|
||||
final EncryptionInfo infoActual2;
|
||||
final byte[] payloadActual, encPackActual;
|
||||
final long decPackLenActual;
|
||||
try (NPOIFSFileSystem nfs = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
|
||||
infoActual2 = new EncryptionInfo(nfs.getRoot());
|
||||
Decryptor decActual = Decryptor.getInstance(infoActual2);
|
||||
boolean passed = decActual.verifyPassword(pass);
|
||||
assertTrue("Unable to process: document is encrypted", passed);
|
||||
|
||||
// extract the payload
|
||||
is = decActual.getDataStream(nfs);
|
||||
byte payloadActual[] = IOUtils.toByteArray(is);
|
||||
is.close();
|
||||
// extract the payload
|
||||
try (InputStream is = decActual.getDataStream(nfs)) {
|
||||
payloadActual = IOUtils.toByteArray(is);
|
||||
}
|
||||
|
||||
long decPackLenActual = decActual.getLength();
|
||||
decPackLenActual = decActual.getLength();
|
||||
|
||||
is = nfs.getRoot().createDocumentInputStream(Decryptor.DEFAULT_POIFS_ENTRY);
|
||||
is = new BoundedInputStream(is, is.available()-16); // ignore padding block
|
||||
byte encPackActual[] = IOUtils.toByteArray(is);
|
||||
is.close();
|
||||
|
||||
// listDir(nfs.getRoot(), "copy", "");
|
||||
|
||||
nfs.close();
|
||||
final DirectoryNode root = nfs.getRoot();
|
||||
final DocumentEntry entry = (DocumentEntry)root.getEntry(Decryptor.DEFAULT_POIFS_ENTRY);
|
||||
try (InputStream is = root.createDocumentInputStream(entry)) {
|
||||
// ignore padding block
|
||||
encPackActual = IOUtils.toByteArray(is, entry.getSize()-16);
|
||||
}
|
||||
}
|
||||
|
||||
AgileEncryptionHeader aehExpected = (AgileEncryptionHeader)infoExpected.getHeader();
|
||||
AgileEncryptionHeader aehActual = (AgileEncryptionHeader)infoActual.getHeader();
|
||||
@ -186,32 +196,33 @@ public class TestEncryptor {
|
||||
@Test
|
||||
public void standardEncryption() throws Exception {
|
||||
File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-solrcell.docx");
|
||||
String pass = "solrcell";
|
||||
final String pass = "solrcell";
|
||||
|
||||
NPOIFSFileSystem nfs = new NPOIFSFileSystem(file);
|
||||
final byte[] payloadExpected;
|
||||
final EncryptionInfo infoExpected;
|
||||
final Decryptor d;
|
||||
try (NPOIFSFileSystem nfs = new NPOIFSFileSystem(file, true)) {
|
||||
|
||||
// Check the encryption details
|
||||
EncryptionInfo infoExpected = new EncryptionInfo(nfs);
|
||||
Decryptor d = Decryptor.getInstance(infoExpected);
|
||||
boolean passed = d.verifyPassword(pass);
|
||||
assertTrue("Unable to process: document is encrypted", passed);
|
||||
// Check the encryption details
|
||||
infoExpected = new EncryptionInfo(nfs);
|
||||
d = Decryptor.getInstance(infoExpected);
|
||||
boolean passed = d.verifyPassword(pass);
|
||||
assertTrue("Unable to process: document is encrypted", passed);
|
||||
|
||||
// extract the payload
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
InputStream is = d.getDataStream(nfs);
|
||||
IOUtils.copy(is, bos);
|
||||
is.close();
|
||||
nfs.close();
|
||||
byte payloadExpected[] = bos.toByteArray();
|
||||
// extract the payload
|
||||
try (InputStream is = d.getDataStream(nfs)) {
|
||||
payloadExpected = IOUtils.toByteArray(is);
|
||||
}
|
||||
}
|
||||
|
||||
// check that same verifier/salt lead to same hashes
|
||||
byte verifierSaltExpected[] = infoExpected.getVerifier().getSalt();
|
||||
byte verifierExpected[] = d.getVerifier();
|
||||
byte keySpec[] = d.getSecretKey().getEncoded();
|
||||
byte keySalt[] = infoExpected.getHeader().getKeySalt();
|
||||
final byte verifierSaltExpected[] = infoExpected.getVerifier().getSalt();
|
||||
final byte verifierExpected[] = d.getVerifier();
|
||||
final byte keySpec[] = d.getSecretKey().getEncoded();
|
||||
final byte keySalt[] = infoExpected.getHeader().getKeySalt();
|
||||
|
||||
|
||||
EncryptionInfo infoActual = new EncryptionInfo(
|
||||
final EncryptionInfo infoActual = new EncryptionInfo(
|
||||
EncryptionMode.standard
|
||||
, infoExpected.getVerifier().getCipherAlgorithm()
|
||||
, infoExpected.getVerifier().getHashAlgorithm()
|
||||
@ -220,7 +231,7 @@ public class TestEncryptor {
|
||||
, infoExpected.getVerifier().getChainingMode()
|
||||
);
|
||||
|
||||
Encryptor e = Encryptor.getInstance(infoActual);
|
||||
final Encryptor e = Encryptor.getInstance(infoActual);
|
||||
e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, null);
|
||||
|
||||
assertArrayEquals(infoExpected.getVerifier().getEncryptedVerifier(), infoActual.getVerifier().getEncryptedVerifier());
|
||||
@ -229,45 +240,40 @@ public class TestEncryptor {
|
||||
// now we use a newly generated salt/verifier and check
|
||||
// if the file content is still the same
|
||||
|
||||
infoActual = new EncryptionInfo(
|
||||
EncryptionMode.standard
|
||||
, infoExpected.getVerifier().getCipherAlgorithm()
|
||||
, infoExpected.getVerifier().getHashAlgorithm()
|
||||
, infoExpected.getHeader().getKeySize()
|
||||
, infoExpected.getHeader().getBlockSize()
|
||||
, infoExpected.getVerifier().getChainingMode()
|
||||
);
|
||||
final byte[] encBytes;
|
||||
try (POIFSFileSystem fs = new POIFSFileSystem()) {
|
||||
|
||||
e = Encryptor.getInstance(infoActual);
|
||||
e.confirmPassword(pass);
|
||||
final EncryptionInfo infoActual2 = new EncryptionInfo(
|
||||
EncryptionMode.standard
|
||||
, infoExpected.getVerifier().getCipherAlgorithm()
|
||||
, infoExpected.getVerifier().getHashAlgorithm()
|
||||
, infoExpected.getHeader().getKeySize()
|
||||
, infoExpected.getHeader().getBlockSize()
|
||||
, infoExpected.getVerifier().getChainingMode()
|
||||
);
|
||||
|
||||
POIFSFileSystem fs = new POIFSFileSystem();
|
||||
OutputStream os = e.getDataStream(fs);
|
||||
IOUtils.copy(new ByteArrayInputStream(payloadExpected), os);
|
||||
os.close();
|
||||
final Encryptor e2 = Encryptor.getInstance(infoActual2);
|
||||
e2.confirmPassword(pass);
|
||||
|
||||
bos.reset();
|
||||
fs.writeFilesystem(bos);
|
||||
try (OutputStream os = e2.getDataStream(fs)) {
|
||||
os.write(payloadExpected);
|
||||
}
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
|
||||
fs.writeFilesystem(bos);
|
||||
encBytes = bos.toByteArray();
|
||||
}
|
||||
|
||||
// FileOutputStream fos = new FileOutputStream("encrypted.docx");
|
||||
// IOUtils.copy(bis, fos);
|
||||
// fos.close();
|
||||
// bis.reset();
|
||||
final byte[] payloadActual;
|
||||
try (NPOIFSFileSystem nfs = new NPOIFSFileSystem(new ByteArrayInputStream(encBytes))) {
|
||||
final EncryptionInfo ei = new EncryptionInfo(nfs);
|
||||
Decryptor d2 = Decryptor.getInstance(ei);
|
||||
assertTrue("Unable to process: document is encrypted", d2.verifyPassword(pass));
|
||||
|
||||
nfs = new NPOIFSFileSystem(bis);
|
||||
infoExpected = new EncryptionInfo(nfs);
|
||||
d = Decryptor.getInstance(infoExpected);
|
||||
passed = d.verifyPassword(pass);
|
||||
assertTrue("Unable to process: document is encrypted", passed);
|
||||
|
||||
bos.reset();
|
||||
is = d.getDataStream(nfs);
|
||||
IOUtils.copy(is, bos);
|
||||
is.close();
|
||||
nfs.close();
|
||||
byte payloadActual[] = bos.toByteArray();
|
||||
try (InputStream is = d2.getDataStream(nfs)) {
|
||||
payloadActual = IOUtils.toByteArray(is);
|
||||
}
|
||||
}
|
||||
|
||||
assertArrayEquals(payloadExpected, payloadActual);
|
||||
}
|
||||
@ -281,85 +287,87 @@ public class TestEncryptor {
|
||||
@Test
|
||||
public void encryptPackageWithoutCoreProperties() throws Exception {
|
||||
// Open our file without core properties
|
||||
File inp = POIDataSamples.getOpenXML4JInstance().getFile("OPCCompliance_NoCoreProperties.xlsx");
|
||||
OPCPackage pkg = OPCPackage.open(inp.getPath());
|
||||
final byte[] encBytes;
|
||||
try (InputStream is = POIDataSamples.getOpenXML4JInstance().openResourceAsStream("OPCCompliance_NoCoreProperties.xlsx");
|
||||
OPCPackage pkg = OPCPackage.open(is)) {
|
||||
|
||||
// It doesn't have any core properties yet
|
||||
assertEquals(0, pkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
|
||||
assertNotNull(pkg.getPackageProperties());
|
||||
assertNotNull(pkg.getPackageProperties().getLanguageProperty());
|
||||
assertNull(pkg.getPackageProperties().getLanguageProperty().getValue());
|
||||
// It doesn't have any core properties yet
|
||||
assertEquals(0, pkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
|
||||
assertNotNull(pkg.getPackageProperties());
|
||||
assertNotNull(pkg.getPackageProperties().getLanguageProperty());
|
||||
assertNull(pkg.getPackageProperties().getLanguageProperty().getValue());
|
||||
|
||||
// Encrypt it
|
||||
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
|
||||
NPOIFSFileSystem fs = new NPOIFSFileSystem();
|
||||
// Encrypt it
|
||||
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
|
||||
Encryptor enc = info.getEncryptor();
|
||||
enc.confirmPassword("password");
|
||||
|
||||
Encryptor enc = info.getEncryptor();
|
||||
enc.confirmPassword("password");
|
||||
OutputStream os = enc.getDataStream(fs);
|
||||
pkg.save(os);
|
||||
os.close();
|
||||
pkg.revert();
|
||||
try (NPOIFSFileSystem fs = new NPOIFSFileSystem()) {
|
||||
|
||||
// Save the resulting OLE2 document, and re-open it
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
fs.writeFilesystem(baos);
|
||||
fs.close();
|
||||
try (OutputStream os = enc.getDataStream(fs)) {
|
||||
pkg.save(os);
|
||||
}
|
||||
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
NPOIFSFileSystem inpFS = new NPOIFSFileSystem(bais);
|
||||
// Save the resulting OLE2 document, and re-open it
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
fs.writeFilesystem(baos);
|
||||
encBytes = baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
// Check we can decrypt it
|
||||
info = new EncryptionInfo(inpFS);
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
assertEquals(true, d.verifyPassword("password"));
|
||||
|
||||
OPCPackage inpPkg = OPCPackage.open(d.getDataStream(inpFS));
|
||||
try (NPOIFSFileSystem inpFS = new NPOIFSFileSystem(new ByteArrayInputStream(encBytes))) {
|
||||
// Check we can decrypt it
|
||||
EncryptionInfo info = new EncryptionInfo(inpFS);
|
||||
Decryptor d = Decryptor.getInstance(info);
|
||||
assertEquals(true, d.verifyPassword("password"));
|
||||
|
||||
// Check it now has empty core properties
|
||||
assertEquals(1, inpPkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
|
||||
assertNotNull(inpPkg.getPackageProperties());
|
||||
assertNotNull(inpPkg.getPackageProperties().getLanguageProperty());
|
||||
assertNull(inpPkg.getPackageProperties().getLanguageProperty().getValue());
|
||||
try (OPCPackage inpPkg = OPCPackage.open(d.getDataStream(inpFS))) {
|
||||
// Check it now has empty core properties
|
||||
assertEquals(1, inpPkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
|
||||
assertNotNull(inpPkg.getPackageProperties());
|
||||
assertNotNull(inpPkg.getPackageProperties().getLanguageProperty());
|
||||
assertNull(inpPkg.getPackageProperties().getLanguageProperty().getValue());
|
||||
|
||||
inpPkg.close();
|
||||
inpFS.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void inPlaceRewrite() throws Exception {
|
||||
File f = TempFile.createTempFile("protected_agile", ".docx");
|
||||
// File f = new File("protected_agile.docx");
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
InputStream fis = POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx");
|
||||
IOUtils.copy(fis, fos);
|
||||
fis.close();
|
||||
fos.close();
|
||||
|
||||
NPOIFSFileSystem fs = new NPOIFSFileSystem(f, false);
|
||||
try (FileOutputStream fos = new FileOutputStream(f);
|
||||
InputStream fis = POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx")) {
|
||||
IOUtils.copy(fis, fos);
|
||||
}
|
||||
|
||||
// decrypt the protected file - in this case it was encrypted with the default password
|
||||
EncryptionInfo encInfo = new EncryptionInfo(fs);
|
||||
Decryptor d = encInfo.getDecryptor();
|
||||
boolean b = d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
||||
assertTrue(b);
|
||||
try (NPOIFSFileSystem fs = new NPOIFSFileSystem(f, false)) {
|
||||
|
||||
// do some strange things with it ;)
|
||||
InputStream docIS = d.getDataStream(fs);
|
||||
XWPFDocument docx = new XWPFDocument(docIS);
|
||||
docx.getParagraphArray(0).insertNewRun(0).setText("POI was here! All your base are belong to us!");
|
||||
docx.getParagraphArray(0).insertNewRun(1).addBreak();
|
||||
// decrypt the protected file - in this case it was encrypted with the default password
|
||||
EncryptionInfo encInfo = new EncryptionInfo(fs);
|
||||
Decryptor d = encInfo.getDecryptor();
|
||||
boolean b = d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
||||
assertTrue(b);
|
||||
|
||||
// and encrypt it again
|
||||
Encryptor e = encInfo.getEncryptor();
|
||||
e.confirmPassword("AYBABTU");
|
||||
docx.write(e.getDataStream(fs));
|
||||
docx.close();
|
||||
docIS.close();
|
||||
try (InputStream docIS = d.getDataStream(fs);
|
||||
XWPFDocument docx = new XWPFDocument(docIS)) {
|
||||
|
||||
docx.close();
|
||||
fs.close();
|
||||
// do some strange things with it ;)
|
||||
XWPFParagraph p = docx.getParagraphArray(0);
|
||||
p.insertNewRun(0).setText("POI was here! All your base are belong to us!");
|
||||
p.insertNewRun(1).addBreak();
|
||||
|
||||
// and encrypt it again
|
||||
Encryptor e = encInfo.getEncryptor();
|
||||
e.confirmPassword("AYBABTU");
|
||||
|
||||
try (OutputStream os = e.getDataStream(fs)) {
|
||||
docx.write(os);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -437,21 +445,23 @@ public class TestEncryptor {
|
||||
// existing = getCipher(skey, header.getCipherAlgorithm(), header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
|
||||
// }
|
||||
|
||||
InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
|
||||
POIFSFileSystem fsOrig = new POIFSFileSystem(is);
|
||||
is.close();
|
||||
EncryptionInfo infoOrig = new EncryptionInfo(fsOrig);
|
||||
Decryptor decOrig = infoOrig.getDecryptor();
|
||||
boolean b = decOrig.verifyPassword("Test001!!");
|
||||
assertTrue(b);
|
||||
InputStream decIn = decOrig.getDataStream(fsOrig);
|
||||
byte[] zipInput = IOUtils.toByteArray(decIn);
|
||||
decIn.close();
|
||||
final EncryptionInfo infoOrig;
|
||||
final byte[] zipInput, epOrigBytes;
|
||||
try (InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
|
||||
POIFSFileSystem fsOrig = new POIFSFileSystem(is)) {
|
||||
infoOrig = new EncryptionInfo(fsOrig);
|
||||
Decryptor decOrig = infoOrig.getDecryptor();
|
||||
boolean b = decOrig.verifyPassword("Test001!!");
|
||||
assertTrue(b);
|
||||
try (InputStream decIn = decOrig.getDataStream(fsOrig)) {
|
||||
zipInput = IOUtils.toByteArray(decIn);
|
||||
}
|
||||
|
||||
InputStream epOrig = fsOrig.getRoot().createDocumentInputStream("EncryptedPackage");
|
||||
// ignore the 16 padding bytes
|
||||
byte[] epOrigBytes = IOUtils.toByteArray(epOrig, 9400);
|
||||
epOrig.close();
|
||||
try (InputStream epOrig = fsOrig.getRoot().createDocumentInputStream("EncryptedPackage")) {
|
||||
// ignore the 16 padding bytes
|
||||
epOrigBytes = IOUtils.toByteArray(epOrig, 9400);
|
||||
}
|
||||
}
|
||||
|
||||
EncryptionInfo eiNew = new EncryptionInfo(EncryptionMode.agile);
|
||||
AgileEncryptionHeader aehHeader = (AgileEncryptionHeader)eiNew.getHeader();
|
||||
@ -472,26 +482,29 @@ public class TestEncryptor {
|
||||
infoOrig.getVerifier().getSalt(),
|
||||
infoOrig.getDecryptor().getIntegrityHmacKey()
|
||||
);
|
||||
NPOIFSFileSystem fsNew = new NPOIFSFileSystem();
|
||||
OutputStream os = enc.getDataStream(fsNew);
|
||||
os.write(zipInput);
|
||||
os.close();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
fsNew.writeFilesystem(bos);
|
||||
fsNew.close();
|
||||
final byte[] epNewBytes;
|
||||
final EncryptionInfo infoReload;
|
||||
try (NPOIFSFileSystem fsNew = new NPOIFSFileSystem()) {
|
||||
try (OutputStream os = enc.getDataStream(fsNew)) {
|
||||
os.write(zipInput);
|
||||
}
|
||||
|
||||
NPOIFSFileSystem fsReload = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
|
||||
InputStream epReload = fsReload.getRoot().createDocumentInputStream("EncryptedPackage");
|
||||
byte[] epNewBytes = IOUtils.toByteArray(epReload, 9400);
|
||||
epReload.close();
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
fsNew.writeFilesystem(bos);
|
||||
|
||||
try (NPOIFSFileSystem fsReload = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()))) {
|
||||
infoReload = new EncryptionInfo(fsReload);
|
||||
try (InputStream epReload = fsReload.getRoot().createDocumentInputStream("EncryptedPackage")) {
|
||||
epNewBytes = IOUtils.toByteArray(epReload, 9400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertArrayEquals(epOrigBytes, epNewBytes);
|
||||
|
||||
EncryptionInfo infoReload = new EncryptionInfo(fsOrig);
|
||||
Decryptor decReload = infoReload.getDecryptor();
|
||||
b = decReload.verifyPassword("Test001!!");
|
||||
assertTrue(b);
|
||||
assertTrue(decReload.verifyPassword("Test001!!"));
|
||||
|
||||
AgileEncryptionHeader aehOrig = (AgileEncryptionHeader)infoOrig.getHeader();
|
||||
AgileEncryptionHeader aehReload = (AgileEncryptionHeader)infoReload.getHeader();
|
||||
@ -529,7 +542,5 @@ public class TestEncryptor {
|
||||
// assertArrayEquals(adOrig.getIntegrityHmacValue(), adReload.getIntegrityHmacValue());
|
||||
assertArrayEquals(adOrig.getSecretKey().getEncoded(), adReload.getSecretKey().getEncoded());
|
||||
assertArrayEquals(adOrig.getVerifier(), adReload.getVerifier());
|
||||
|
||||
fsReload.close();
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +119,9 @@ java.lang.Object#notifyAll()
|
||||
@defaultMessage Don't interrupt threads use FutureUtils#cancel(Future<T>) instead
|
||||
java.util.concurrent.Future#cancel(boolean)
|
||||
|
||||
@defaultMessage Don't use ...InputStream.available() as it gives wrong result for certain streams - use IOUtils.toByteArray to read the stream fully and then count the available bytes
|
||||
java.io.InputStream#available()
|
||||
|
||||
@defaultMessage Unnecessary, inefficient, and confusing conversion of String.toString
|
||||
java.lang.String#toString()
|
||||
|
||||
|
@ -171,7 +171,7 @@ public final class TextSpecInfoAtom extends RecordAtom {
|
||||
public TextSpecInfoRun[] getTextSpecInfoRuns(){
|
||||
LittleEndianByteArrayInputStream bis = new LittleEndianByteArrayInputStream(_data); // NOSONAR
|
||||
List<TextSpecInfoRun> lst = new ArrayList<>();
|
||||
while (bis.available() > 0) {
|
||||
while (bis.getReadIndex() < _data.length) {
|
||||
lst.add(new TextSpecInfoRun(bis));
|
||||
}
|
||||
return lst.toArray(new TextSpecInfoRun[lst.size()]);
|
||||
|
@ -50,52 +50,59 @@ public class HwmfPicture {
|
||||
final HwmfHeader header;
|
||||
|
||||
public HwmfPicture(InputStream inputStream) throws IOException {
|
||||
BufferedInputStream bis = new BufferedInputStream(inputStream, 10000);
|
||||
LittleEndianInputStream leis = new LittleEndianInputStream(bis);
|
||||
placeableHeader = HwmfPlaceableHeader.readHeader(leis);
|
||||
header = new HwmfHeader(leis);
|
||||
|
||||
for (;;) {
|
||||
if (leis.available() < 6) {
|
||||
logger.log(POILogger.ERROR, "unexpected eof - wmf file was truncated");
|
||||
break;
|
||||
}
|
||||
// recordSize in DWORDs
|
||||
long recordSizeLong = leis.readUInt()*2;
|
||||
if (recordSizeLong > Integer.MAX_VALUE) {
|
||||
throw new RecordFormatException("record size can't be > "+Integer.MAX_VALUE);
|
||||
} else if (recordSizeLong < 0L) {
|
||||
throw new RecordFormatException("record size can't be < 0");
|
||||
}
|
||||
int recordSize = (int)recordSizeLong;
|
||||
int recordFunction = leis.readShort();
|
||||
// 4 bytes (recordSize) + 2 bytes (recordFunction)
|
||||
int consumedSize = 6;
|
||||
HwmfRecordType wrt = HwmfRecordType.getById(recordFunction);
|
||||
if (wrt == null) {
|
||||
throw new IOException("unexpected record type: "+recordFunction);
|
||||
}
|
||||
if (wrt == HwmfRecordType.eof) break;
|
||||
if (wrt.clazz == null) {
|
||||
throw new IOException("unsupported record type: "+recordFunction);
|
||||
}
|
||||
try (BufferedInputStream bis = new BufferedInputStream(inputStream, 10000);
|
||||
LittleEndianInputStream leis = new LittleEndianInputStream(bis)) {
|
||||
placeableHeader = HwmfPlaceableHeader.readHeader(leis);
|
||||
header = new HwmfHeader(leis);
|
||||
|
||||
HwmfRecord wr;
|
||||
try {
|
||||
wr = wrt.clazz.newInstance();
|
||||
records.add(wr);
|
||||
} catch (Exception e) {
|
||||
throw (IOException)new IOException("can't create wmf record").initCause(e);
|
||||
}
|
||||
for (;;) {
|
||||
long recordSize;
|
||||
int recordFunction;
|
||||
try {
|
||||
// recordSize in DWORDs
|
||||
long recordSizeLong = leis.readUInt()*2;
|
||||
if (recordSizeLong > Integer.MAX_VALUE) {
|
||||
throw new RecordFormatException("record size can't be > "+Integer.MAX_VALUE);
|
||||
} else if (recordSizeLong < 0L) {
|
||||
throw new RecordFormatException("record size can't be < 0");
|
||||
}
|
||||
recordSize = (int)recordSizeLong;
|
||||
recordFunction = leis.readShort();
|
||||
} catch (Exception e) {
|
||||
logger.log(POILogger.ERROR, "unexpected eof - wmf file was truncated");
|
||||
break;
|
||||
}
|
||||
// 4 bytes (recordSize) + 2 bytes (recordFunction)
|
||||
int consumedSize = 6;
|
||||
HwmfRecordType wrt = HwmfRecordType.getById(recordFunction);
|
||||
if (wrt == null) {
|
||||
throw new IOException("unexpected record type: "+recordFunction);
|
||||
}
|
||||
if (wrt == HwmfRecordType.eof) {
|
||||
break;
|
||||
}
|
||||
if (wrt.clazz == null) {
|
||||
throw new IOException("unsupported record type: "+recordFunction);
|
||||
}
|
||||
|
||||
consumedSize += wr.init(leis, recordSize, recordFunction);
|
||||
int remainingSize = recordSize - consumedSize;
|
||||
if (remainingSize < 0) {
|
||||
throw new RecordFormatException("read too many bytes. record size: "+recordSize + "; comsumed size: "+consumedSize);
|
||||
} else if(remainingSize > 0) {
|
||||
long skipped = IOUtils.skipFully(leis, remainingSize);
|
||||
if (skipped != (long)remainingSize) {
|
||||
throw new RecordFormatException("Tried to skip "+remainingSize + " but skipped: "+skipped);
|
||||
HwmfRecord wr;
|
||||
try {
|
||||
wr = wrt.clazz.newInstance();
|
||||
records.add(wr);
|
||||
} catch (Exception e) {
|
||||
throw (IOException)new IOException("can't create wmf record").initCause(e);
|
||||
}
|
||||
|
||||
consumedSize += wr.init(leis, recordSize, recordFunction);
|
||||
int remainingSize = (int)(recordSize - consumedSize);
|
||||
if (remainingSize < 0) {
|
||||
throw new RecordFormatException("read too many bytes. record size: "+recordSize + "; comsumed size: "+consumedSize);
|
||||
} else if(remainingSize > 0) {
|
||||
long skipped = IOUtils.skipFully(leis, remainingSize);
|
||||
if (skipped != (long)remainingSize) {
|
||||
throw new RecordFormatException("Tried to skip "+remainingSize + " but skipped: "+skipped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
@ -57,32 +58,30 @@ import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestHwmfParsing {
|
||||
|
||||
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
|
||||
|
||||
|
||||
@Test
|
||||
public void parse() throws IOException {
|
||||
File f = POIDataSamples.getSlideShowInstance().getFile("santa.wmf");
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
HwmfPicture wmf = new HwmfPicture(fis);
|
||||
fis.close();
|
||||
List<HwmfRecord> records = wmf.getRecords();
|
||||
assertEquals(581, records.size());
|
||||
try (InputStream fis = samples.openResourceAsStream("santa.wmf")) {
|
||||
HwmfPicture wmf = new HwmfPicture(fis);
|
||||
List<HwmfRecord> records = wmf.getRecords();
|
||||
assertEquals(581, records.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RecordFormatException.class)
|
||||
public void testInfiniteLoop() throws Exception {
|
||||
File f = POIDataSamples.getSlideShowInstance().getFile("61338.wmf");
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(f);
|
||||
HwmfPicture wmf = new HwmfPicture(fis);
|
||||
} finally {
|
||||
fis.close();
|
||||
try (InputStream is = samples.openResourceAsStream("61338.wmf")) {
|
||||
new HwmfPicture(is);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("This is work-in-progress and not a real unit test ...")
|
||||
public void paint() throws IOException {
|
||||
File f = POIDataSamples.getSlideShowInstance().getFile("santa.wmf");
|
||||
File f = samples.getFile("santa.wmf");
|
||||
// File f = new File("bla.wmf");
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
HwmfPicture wmf = new HwmfPicture(fis);
|
||||
|
@ -29,6 +29,7 @@ import java.util.Map;
|
||||
import org.apache.poi.poifs.eventfilesystem.POIFSReader;
|
||||
import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
|
||||
import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
|
||||
/**
|
||||
* Test (Proof of concept) program that employs the
|
||||
@ -110,16 +111,15 @@ public class ReaderWriter
|
||||
@Override
|
||||
public void processPOIFSReaderEvent(final POIFSReaderEvent event)
|
||||
{
|
||||
@SuppressWarnings("resource")
|
||||
DocumentInputStream istream = event.getStream();
|
||||
POIFSDocumentPath path = event.getPath();
|
||||
String name = event.getName();
|
||||
|
||||
try
|
||||
{
|
||||
int size = istream.available();
|
||||
byte[] data = new byte[ istream.available() ];
|
||||
try {
|
||||
byte[] data = IOUtils.toByteArray(istream);
|
||||
int size = data.length;
|
||||
|
||||
istream.read(data);
|
||||
DocumentDescriptor descriptor = new DocumentDescriptor(path,
|
||||
name);
|
||||
|
||||
|
@ -17,22 +17,28 @@
|
||||
|
||||
package org.apache.poi.poifs.filesystem;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.poifs.property.DirectoryProperty;
|
||||
import org.apache.poi.poifs.storage.RawDataBlock;
|
||||
import org.apache.poi.util.SuppressForbidden;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Class to test DocumentInputStream functionality
|
||||
*/
|
||||
public final class TestDocumentInputStream extends TestCase {
|
||||
public final class TestDocumentInputStream {
|
||||
private DocumentNode _workbook_n;
|
||||
private DocumentNode _workbook_o;
|
||||
private byte[] _workbook_data;
|
||||
@ -42,8 +48,8 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
// any block size
|
||||
private static final int _buffer_size = 6;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
int blocks = (_workbook_size + 511) / 512;
|
||||
|
||||
_workbook_data = new byte[ 512 * blocks ];
|
||||
@ -92,6 +98,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
/**
|
||||
* test constructor
|
||||
*/
|
||||
@Test
|
||||
public void testConstructor() throws IOException {
|
||||
DocumentInputStream ostream = new ODocumentInputStream(_workbook_o);
|
||||
DocumentInputStream nstream = new NDocumentInputStream(_workbook_n);
|
||||
@ -99,8 +106,8 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
assertEquals(_workbook_size, _workbook_o.getSize());
|
||||
assertEquals(_workbook_size, _workbook_n.getSize());
|
||||
|
||||
assertEquals(_workbook_size, ostream.available());
|
||||
assertEquals(_workbook_size, nstream.available());
|
||||
assertEquals(_workbook_size, available(ostream));
|
||||
assertEquals(_workbook_size, available(nstream));
|
||||
|
||||
ostream.close();
|
||||
nstream.close();
|
||||
@ -109,23 +116,24 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
/**
|
||||
* test available() behavior
|
||||
*/
|
||||
@Test
|
||||
public void testAvailable() throws IOException {
|
||||
DocumentInputStream ostream = new DocumentInputStream(_workbook_o);
|
||||
DocumentInputStream nstream = new NDocumentInputStream(_workbook_n);
|
||||
|
||||
assertEquals(_workbook_size, ostream.available());
|
||||
assertEquals(_workbook_size, nstream.available());
|
||||
assertEquals(_workbook_size, available(ostream));
|
||||
assertEquals(_workbook_size, available(nstream));
|
||||
ostream.close();
|
||||
nstream.close();
|
||||
|
||||
try {
|
||||
ostream.available();
|
||||
available(ostream);
|
||||
fail("Should have caught IOException");
|
||||
} catch (IllegalStateException ignored) {
|
||||
// as expected
|
||||
}
|
||||
try {
|
||||
nstream.available();
|
||||
available(nstream);
|
||||
fail("Should have caught IOException");
|
||||
} catch (IllegalStateException ignored) {
|
||||
// as expected
|
||||
@ -135,6 +143,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
/**
|
||||
* test mark/reset/markSupported.
|
||||
*/
|
||||
@Test
|
||||
public void testMarkFunctions() throws IOException {
|
||||
byte[] buffer = new byte[ _workbook_size / 5 ];
|
||||
byte[] small_buffer = new byte[212];
|
||||
@ -152,12 +161,12 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
_workbook_data[ j ], buffer[ j ]
|
||||
);
|
||||
}
|
||||
assertEquals(_workbook_size - buffer.length, stream.available());
|
||||
assertEquals(_workbook_size - buffer.length, available(stream));
|
||||
|
||||
// Reset, and check the available goes back to being the
|
||||
// whole of the stream
|
||||
stream.reset();
|
||||
assertEquals(_workbook_size, stream.available());
|
||||
assertEquals(_workbook_size, available(stream));
|
||||
|
||||
|
||||
// Read part of a block
|
||||
@ -168,7 +177,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
_workbook_data[ j ], small_buffer[ j ]
|
||||
);
|
||||
}
|
||||
assertEquals(_workbook_size - small_buffer.length, stream.available());
|
||||
assertEquals(_workbook_size - small_buffer.length, available(stream));
|
||||
stream.mark(0);
|
||||
|
||||
// Read the next part
|
||||
@ -179,11 +188,11 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
_workbook_data[ j+small_buffer.length ], small_buffer[ j ]
|
||||
);
|
||||
}
|
||||
assertEquals(_workbook_size - 2*small_buffer.length, stream.available());
|
||||
assertEquals(_workbook_size - 2*small_buffer.length, available(stream));
|
||||
|
||||
// Reset, check it goes back to where it was
|
||||
stream.reset();
|
||||
assertEquals(_workbook_size - small_buffer.length, stream.available());
|
||||
assertEquals(_workbook_size - small_buffer.length, available(stream));
|
||||
|
||||
// Read
|
||||
stream.read(small_buffer);
|
||||
@ -193,7 +202,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
_workbook_data[ j+small_buffer.length ], small_buffer[ j ]
|
||||
);
|
||||
}
|
||||
assertEquals(_workbook_size - 2*small_buffer.length, stream.available());
|
||||
assertEquals(_workbook_size - 2*small_buffer.length, available(stream));
|
||||
|
||||
|
||||
// Now read at various points
|
||||
@ -236,11 +245,11 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
_workbook_data[ j ], buffer[ j ]
|
||||
);
|
||||
}
|
||||
assertEquals(_workbook_size - buffer.length, stream.available());
|
||||
assertEquals(_workbook_size - buffer.length, available(stream));
|
||||
|
||||
// Read all of it again, check it began at the start again
|
||||
stream.reset();
|
||||
assertEquals(_workbook_size, stream.available());
|
||||
assertEquals(_workbook_size, available(stream));
|
||||
|
||||
stream.read(buffer);
|
||||
for (int j = 0; j < buffer.length; j++) {
|
||||
@ -254,7 +263,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
stream.mark(12);
|
||||
stream.read(buffer);
|
||||
assertEquals(_workbook_size - (2 * buffer.length),
|
||||
stream.available());
|
||||
available(stream));
|
||||
for (int j = buffer.length; j < (2 * buffer.length); j++)
|
||||
{
|
||||
assertEquals("checking byte " + j, _workbook_data[ j ],
|
||||
@ -263,12 +272,12 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
|
||||
// Reset, should go back to only one buffer full read
|
||||
stream.reset();
|
||||
assertEquals(_workbook_size - buffer.length, stream.available());
|
||||
assertEquals(_workbook_size - buffer.length, available(stream));
|
||||
|
||||
// Read the buffer again
|
||||
stream.read(buffer);
|
||||
assertEquals(_workbook_size - (2 * buffer.length),
|
||||
stream.available());
|
||||
available(stream));
|
||||
for (int j = buffer.length; j < (2 * buffer.length); j++)
|
||||
{
|
||||
assertEquals("checking byte " + j, _workbook_data[ j ],
|
||||
@ -281,6 +290,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
/**
|
||||
* test simple read method
|
||||
*/
|
||||
@Test
|
||||
public void testReadSingleByte() throws IOException {
|
||||
DocumentInputStream[] streams = new DocumentInputStream[] {
|
||||
new DocumentInputStream(_workbook_o),
|
||||
@ -297,7 +307,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
( byte ) b);
|
||||
remaining--;
|
||||
assertEquals("checking remaining after reading byte " + j,
|
||||
remaining, stream.available());
|
||||
remaining, available(stream));
|
||||
}
|
||||
|
||||
// Ensure we fell off the end
|
||||
@ -317,6 +327,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
/**
|
||||
* Test buffered read
|
||||
*/
|
||||
@Test
|
||||
public void testBufferRead() throws IOException {
|
||||
DocumentInputStream[] streams = new DocumentInputStream[] {
|
||||
new DocumentInputStream(_workbook_o),
|
||||
@ -333,22 +344,22 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
|
||||
// test reading zero length buffer
|
||||
assertEquals(0, stream.read(new byte[ 0 ]));
|
||||
assertEquals(_workbook_size, stream.available());
|
||||
assertEquals(_workbook_size, available(stream));
|
||||
byte[] buffer = new byte[ _buffer_size ];
|
||||
int offset = 0;
|
||||
|
||||
while (stream.available() >= buffer.length)
|
||||
while (available(stream) >= buffer.length)
|
||||
{
|
||||
assertEquals(_buffer_size, stream.read(buffer));
|
||||
for (byte data : buffer) {
|
||||
for (byte element : buffer) {
|
||||
assertEquals("in main loop, byte " + offset,
|
||||
_workbook_data[ offset ], data);
|
||||
_workbook_data[ offset ], element);
|
||||
offset++;
|
||||
}
|
||||
assertEquals("offset " + offset, _workbook_size - offset,
|
||||
stream.available());
|
||||
available(stream));
|
||||
}
|
||||
assertEquals(_workbook_size % _buffer_size, stream.available());
|
||||
assertEquals(_workbook_size % _buffer_size, available(stream));
|
||||
Arrays.fill(buffer, ( byte ) 0);
|
||||
int count = stream.read(buffer);
|
||||
|
||||
@ -378,6 +389,7 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
/**
|
||||
* Test complex buffered read
|
||||
*/
|
||||
@Test
|
||||
public void testComplexBufferRead() throws IOException {
|
||||
DocumentInputStream[] streams = new DocumentInputStream[] {
|
||||
new DocumentInputStream(_workbook_o),
|
||||
@ -413,11 +425,11 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
|
||||
// test reading zero
|
||||
assertEquals(0, stream.read(new byte[ 5 ], 0, 0));
|
||||
assertEquals(_workbook_size, stream.available());
|
||||
assertEquals(_workbook_size, available(stream));
|
||||
byte[] buffer = new byte[ _workbook_size ];
|
||||
int offset = 0;
|
||||
|
||||
while (stream.available() >= _buffer_size)
|
||||
while (available(stream) >= _buffer_size)
|
||||
{
|
||||
Arrays.fill(buffer, ( byte ) 0);
|
||||
assertEquals(_buffer_size,
|
||||
@ -437,9 +449,9 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
}
|
||||
offset += _buffer_size;
|
||||
assertEquals("offset " + offset, _workbook_size - offset,
|
||||
stream.available());
|
||||
available(stream));
|
||||
}
|
||||
assertEquals(_workbook_size % _buffer_size, stream.available());
|
||||
assertEquals(_workbook_size % _buffer_size, available(stream));
|
||||
Arrays.fill(buffer, ( byte ) 0);
|
||||
int count = stream.read(buffer, offset,
|
||||
_workbook_size % _buffer_size);
|
||||
@ -474,38 +486,40 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
/**
|
||||
* Tests that we can skip within the stream
|
||||
*/
|
||||
@Test
|
||||
public void testSkip() throws IOException {
|
||||
DocumentInputStream[] streams = new DocumentInputStream[] {
|
||||
new DocumentInputStream(_workbook_o),
|
||||
new NDocumentInputStream(_workbook_n)
|
||||
};
|
||||
for(DocumentInputStream stream : streams) {
|
||||
assertEquals(_workbook_size, stream.available());
|
||||
int count = stream.available();
|
||||
assertEquals(_workbook_size, available(stream));
|
||||
int count = available(stream);
|
||||
|
||||
while (stream.available() >= _buffer_size) {
|
||||
while (available(stream) >= _buffer_size) {
|
||||
assertEquals(_buffer_size, stream.skip(_buffer_size));
|
||||
count -= _buffer_size;
|
||||
assertEquals(count, stream.available());
|
||||
assertEquals(count, available(stream));
|
||||
}
|
||||
assertEquals(_workbook_size % _buffer_size,
|
||||
stream.skip(_buffer_size));
|
||||
assertEquals(0, stream.available());
|
||||
assertEquals(0, available(stream));
|
||||
stream.reset();
|
||||
assertEquals(_workbook_size, stream.available());
|
||||
assertEquals(_workbook_size, available(stream));
|
||||
assertEquals(_workbook_size, stream.skip(_workbook_size * 2));
|
||||
assertEquals(0, stream.available());
|
||||
assertEquals(0, available(stream));
|
||||
stream.reset();
|
||||
assertEquals(_workbook_size, stream.available());
|
||||
assertEquals(_workbook_size, available(stream));
|
||||
assertEquals(_workbook_size,
|
||||
stream.skip(2 + ( long ) Integer.MAX_VALUE));
|
||||
assertEquals(0, stream.available());
|
||||
assertEquals(0, available(stream));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can read files at multiple levels down the tree
|
||||
*/
|
||||
@Test
|
||||
public void testReadMultipleTreeLevels() throws Exception {
|
||||
final POIDataSamples _samples = POIDataSamples.getPublisherInstance();
|
||||
File sample = _samples.getFile("Sample.pub");
|
||||
@ -551,4 +565,9 @@ public final class TestDocumentInputStream extends TestCase {
|
||||
npoifs.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressForbidden("just for testing")
|
||||
private static int available(InputStream is) throws IOException {
|
||||
return is.available();
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import org.apache.poi.poifs.storage.BATBlock;
|
||||
import org.apache.poi.poifs.storage.BlockAllocationTableReader;
|
||||
import org.apache.poi.poifs.storage.HeaderBlock;
|
||||
import org.apache.poi.poifs.storage.RawDataBlockList;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
|
||||
/**
|
||||
* Tests for the older OPOIFS-based POIFSFileSystem
|
||||
@ -285,13 +286,8 @@ public final class TestPOIFSFileSystem extends TestCase {
|
||||
checkAllDirectoryContents((DirectoryEntry)entry);
|
||||
} else {
|
||||
DocumentNode doc = (DocumentNode) entry;
|
||||
DocumentInputStream dis = new DocumentInputStream(doc);
|
||||
try {
|
||||
int numBytes = dis.available();
|
||||
byte[] data = new byte [numBytes];
|
||||
dis.read(data);
|
||||
} finally {
|
||||
dis.close();
|
||||
try (DocumentInputStream dis = new DocumentInputStream(doc)) {
|
||||
IOUtils.toByteArray(dis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +172,29 @@ public final class TestIOUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RecordFormatException.class)
|
||||
public void testMaxLengthTooLong() throws IOException {
|
||||
try (InputStream is = new FileInputStream(TMP)) {
|
||||
IOUtils.toByteArray(is, Integer.MAX_VALUE, 100);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxLengthIgnored() throws IOException {
|
||||
try (InputStream is = new FileInputStream(TMP)) {
|
||||
IOUtils.toByteArray(is, 90, Integer.MAX_VALUE);
|
||||
IOUtils.toByteArray(is, 90, 100);
|
||||
IOUtils.toByteArray(is, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RecordFormatException.class)
|
||||
public void testMaxLengthInvalid() throws IOException {
|
||||
try (InputStream is = new FileInputStream(TMP)) {
|
||||
IOUtils.toByteArray(is, 90, 80);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWonkyInputStream() throws IOException {
|
||||
long skipped = IOUtils.skipFully(new WonkyInputStream(), 10000);
|
||||
|
@ -258,10 +258,14 @@ public final class TestLittleEndian {
|
||||
InputStream stream = new ByteArrayInputStream(_good_array);
|
||||
int count = 0;
|
||||
|
||||
while (stream.available() > 0) {
|
||||
short value = LittleEndian.readShort(stream);
|
||||
assertEquals(value, expected_value);
|
||||
count++;
|
||||
while (true) {
|
||||
try {
|
||||
short value = LittleEndian.readShort(stream);
|
||||
assertEquals(value, expected_value);
|
||||
count++;
|
||||
} catch (BufferUnderrunException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertEquals(count,
|
||||
_good_array.length / LittleEndianConsts.SHORT_SIZE);
|
||||
@ -283,10 +287,14 @@ public final class TestLittleEndian {
|
||||
InputStream stream = new ByteArrayInputStream(_good_array);
|
||||
int count = 0;
|
||||
|
||||
while (stream.available() > 0) {
|
||||
int value = LittleEndian.readInt(stream);
|
||||
assertEquals(value, expected_value);
|
||||
count++;
|
||||
while (true) {
|
||||
try {
|
||||
int value = LittleEndian.readInt(stream);
|
||||
assertEquals(value, expected_value);
|
||||
count++;
|
||||
} catch (BufferUnderrunException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertEquals(count, _good_array.length / LittleEndianConsts.INT_SIZE);
|
||||
stream = new ByteArrayInputStream(_bad_array);
|
||||
@ -308,10 +316,14 @@ public final class TestLittleEndian {
|
||||
InputStream stream = new ByteArrayInputStream(_good_array);
|
||||
int count = 0;
|
||||
|
||||
while (stream.available() > 0) {
|
||||
long value = LittleEndian.readLong(stream);
|
||||
assertEquals(value, expected_value);
|
||||
count++;
|
||||
while (true) {
|
||||
try {
|
||||
long value = LittleEndian.readLong(stream);
|
||||
assertEquals(value, expected_value);
|
||||
count++;
|
||||
} catch (BufferUnderrunException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertEquals(count,
|
||||
_good_array.length / LittleEndianConsts.LONG_SIZE);
|
||||
@ -324,21 +336,17 @@ public final class TestLittleEndian {
|
||||
}
|
||||
}
|
||||
|
||||
// public void testReadFromStream() throws IOException {
|
||||
// int actual;
|
||||
// actual = LittleEndian.readUShort(new ByteArrayInputStream(new byte[] { 5, -128, }));
|
||||
// assertEquals(32773, actual);
|
||||
//
|
||||
// actual = LittleEndian.readUShort(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, }));
|
||||
// assertEquals(513, actual);
|
||||
//
|
||||
// try {
|
||||
// LittleEndian.readInt(new ByteArrayInputStream(new byte[] { 1, 2, 3, }));
|
||||
// fail("Should have caught BufferUnderrunException");
|
||||
// } catch (BufferUnderrunException ignored) {
|
||||
// // as expected
|
||||
// }
|
||||
// }
|
||||
@Test(expected = BufferUnderrunException.class)
|
||||
public void testReadFromStream() throws IOException {
|
||||
int actual;
|
||||
actual = LittleEndian.readUShort(new ByteArrayInputStream(new byte[] { 5, -128, }));
|
||||
assertEquals(32773, actual);
|
||||
|
||||
actual = LittleEndian.readUShort(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, }));
|
||||
assertEquals(513, actual);
|
||||
|
||||
LittleEndian.readInt(new ByteArrayInputStream(new byte[] { 1, 2, 3, }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsignedByteToInt() {
|
||||
|
Loading…
Reference in New Issue
Block a user