Browse Source

Bug 51891 - Fix StringIndexOutOfBoundsException : Ole10Native.<init> (parsing word file)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1563483 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_3_11_BETA1
Andreas Beeker 10 years ago
parent
commit
e484fd75d0

+ 1
- 0
src/java/org/apache/poi/hpsf/ClassID.java View File

@@ -40,6 +40,7 @@ public class ClassID
public static final ClassID WORD95 = new ClassID("{00020900-0000-0000-C000-000000000046}");
public static final ClassID POWERPOINT97 = new ClassID("{64818D10-4F9B-11CF-86EA-00AA00B929E8}");
public static final ClassID POWERPOINT95 = new ClassID("{EA7BAE70-FB3B-11CD-A903-00AA00510EA3}");
public static final ClassID EQUATION30 = new ClassID("{0002CE02-0000-0000-C000-000000000046}");
/**

+ 363
- 327
src/java/org/apache/poi/poifs/filesystem/Ole10Native.java View File

@@ -17,14 +17,13 @@

package org.apache.poi.poifs.filesystem;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutputStream;
import org.apache.poi.util.StringUtil;
/**
@@ -35,341 +34,378 @@ import org.apache.poi.util.StringUtil;
*/
public class Ole10Native {

public static final String OLE10_NATIVE = "\u0001Ole10Native";
protected static final String ISO1 = "ISO-8859-1";

// (the fields as they appear in the raw record:)
private int totalSize; // 4 bytes, total size of record not including this field
private short flags1 = 2; // 2 bytes, unknown, mostly [02 00]
private String label; // ASCIIZ, stored in this field without the terminating zero
private String fileName; // ASCIIZ, stored in this field without the terminating zero
private short flags2 = 0; // 2 bytes, unknown, mostly [00 00]
private short unknown1 = 3; // see below
private String command; // ASCIIZ, stored in this field without the terminating zero
private byte[] dataBuffer; // varying size, the actual native data
private short flags3 = 0; // some final flags? or zero terminators?, sometimes not there

/**
* Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
* to include a stream &quot;{01}Ole10Native&quot; which contains the actual
* data relevant for this class.
*
* @param poifs POI Filesystem object
* @return Returns an instance of this class
* @throws IOException on IO error
* @throws Ole10NativeException on invalid or unexcepted data format
*/
public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {
return createFromEmbeddedOleObject(poifs.getRoot());
}
public static final String OLE10_NATIVE = "\u0001Ole10Native";
protected static final String ISO1 = "ISO-8859-1";
// (the fields as they appear in the raw record:)
private int totalSize; // 4 bytes, total size of record not including this field
private short flags1 = 2; // 2 bytes, unknown, mostly [02 00]
private String label; // ASCIIZ, stored in this field without the terminating zero
private String fileName; // ASCIIZ, stored in this field without the terminating zero
private short flags2 = 0; // 2 bytes, unknown, mostly [00 00]
private short unknown1 = 3; // see below
private String command; // ASCIIZ, stored in this field without the terminating zero
private byte[] dataBuffer; // varying size, the actual native data
private short flags3 = 0; // some final flags? or zero terminators?, sometimes not there
/**
* the field encoding mode - merely a try-and-error guess ...
**/
private enum EncodingMode {
/**
* the data is stored in parsed format - including label, command, etc.
*/
parsed,
/**
* the data is stored raw after the length field
*/
unparsed,
/**
* the data is stored raw after the length field and the flags1 field
*/
compact;
}
private EncodingMode mode;
/**
* Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
* to include a stream &quot;{01}Ole10Native&quot; which contains the actual
* data relevant for this class.
*
* @param poifs POI Filesystem object
* @return Returns an instance of this class
* @throws IOException on IO error
* @throws Ole10NativeException on invalid or unexcepted data format
*/
public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {
return createFromEmbeddedOleObject(poifs.getRoot());
}
/**
* Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
* to include a stream &quot;{01}Ole10Native&quot; which contains the actual
* data relevant for this class.
*
* @param directory POI Filesystem object
* @return Returns an instance of this class
* @throws IOException on IO error
* @throws Ole10NativeException on invalid or unexcepted data format
*/
public static Ole10Native createFromEmbeddedOleObject(DirectoryNode directory) throws IOException, Ole10NativeException {
DocumentEntry nativeEntry =
(DocumentEntry)directory.getEntry(OLE10_NATIVE);
byte[] data = new byte[nativeEntry.getSize()];
directory.createDocumentInputStream(nativeEntry).read(data);
/**
* Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
* to include a stream &quot;{01}Ole10Native&quot; which contains the actual
* data relevant for this class.
*
* @param directory POI Filesystem object
* @return Returns an instance of this class
* @throws IOException on IO error
* @throws Ole10NativeException on invalid or unexcepted data format
*/
public static Ole10Native createFromEmbeddedOleObject(DirectoryNode directory) throws IOException, Ole10NativeException {
boolean plain = false;
return new Ole10Native(data, 0);
}
/**
* Creates an instance and fills the fields based on ... the fields
*/
public Ole10Native(String label, String filename, String command, byte[] data) {
setLabel(label);
setFileName(filename);
setCommand(command);
setDataBuffer(data);
mode = EncodingMode.parsed;
}
try {
directory.getEntry("\u0001Ole10ItemName");
plain = true;
} catch (FileNotFoundException ex) {
plain = false;
}
DocumentEntry nativeEntry =
(DocumentEntry)directory.getEntry(OLE10_NATIVE);
byte[] data = new byte[nativeEntry.getSize()];
directory.createDocumentInputStream(nativeEntry).read(data);
/**
* Creates an instance and fills the fields based on the data in the given buffer.
*
* @param data The buffer containing the Ole10Native record
* @param offset The start offset of the record in the buffer
* @param plain as of POI 3.11 this parameter is ignored
* @throws Ole10NativeException on invalid or unexcepted data format
*
* @deprecated parameter plain is ignored, use {@link #Ole10Native(byte[],int)}
*/
public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {
this(data, offset);
}
/**
* Creates an instance and fills the fields based on the data in the given buffer.
*
* @param data The buffer containing the Ole10Native record
* @param offset The start offset of the record in the buffer
* @throws Ole10NativeException on invalid or unexcepted data format
*/
public Ole10Native(byte[] data, int offset) throws Ole10NativeException {
int ofs = offset; // current offset, initialized to start
if (data.length < offset + 2) {
throw new Ole10NativeException("data is too small");
}
totalSize = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;
mode = EncodingMode.unparsed;
if (LittleEndian.getShort(data, ofs) == 2) {
// some files like equations don't have a valid filename,
// but somehow encode the formula right away in the ole10 header
if (Character.isISOControl(data[ofs+LittleEndianConsts.SHORT_SIZE])) {
mode = EncodingMode.compact;
} else {
mode = EncodingMode.parsed;
}
}
return new Ole10Native(data, 0, plain);
}
/**
* Creates an instance and fills the fields based on ... the fields
*/
public Ole10Native(String label, String filename, String command, byte[] data) {
setLabel(label);
setFileName(filename);
setCommand(command);
setDataBuffer(data);
}
/**
* Creates an instance and fills the fields based on the data in the given buffer.
*
* @param data The buffer containing the Ole10Native record
* @param offset The start offset of the record in the buffer
* @throws Ole10NativeException on invalid or unexcepted data format
*/
public Ole10Native(byte[] data, int offset) throws Ole10NativeException {
this(data, offset, false);
}
/**
* Creates an instance and fills the fields based on the data in the given buffer.
*
* @param data The buffer containing the Ole10Native record
* @param offset The start offset of the record in the buffer
* @param plain Specified 'plain' format without filename
* @throws Ole10NativeException on invalid or unexcepted data format
*/
public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {
int ofs = offset; // current offset, initialized to start
int dataSize;
switch (mode) {
case parsed: {
flags1 = LittleEndian.getShort(data, ofs);
// structured format
ofs += LittleEndianConsts.SHORT_SIZE;
int len = getStringLength(data, ofs);
label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
len = getStringLength(data, ofs);
fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
flags2 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
unknown1 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
len = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;
command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
if (totalSize < ofs) {
throw new Ole10NativeException("Invalid Ole10Native");
}
dataSize = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;
if (dataSize < 0 || totalSize - (ofs - LittleEndianConsts.INT_SIZE) < dataSize) {
throw new Ole10NativeException("Invalid Ole10Native");
}
break;
}
case compact:
flags1 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
dataSize = totalSize - LittleEndianConsts.SHORT_SIZE;
break;
default:
case unparsed:
dataSize = totalSize;
break;
}
dataBuffer = new byte[dataSize];
System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
ofs += dataSize;
}
if (data.length<offset+2) {
throw new Ole10NativeException("data is too small");
/*
* Helper - determine length of zero terminated string (ASCIIZ).
*/
private static int getStringLength(byte[] data, int ofs) {
int len = 0;
while (len + ofs < data.length && data[ofs + len] != 0) {
len++;
}
len++;
return len;
}
totalSize = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;
/**
* Returns the value of the totalSize field - the total length of the
* structure is totalSize + 4 (value of this field + size of this field).
*
* @return the totalSize
*/
public int getTotalSize() {
return totalSize;
}
if (plain) {
dataBuffer = new byte[totalSize-4];
System.arraycopy(data, 4, dataBuffer, 0, dataBuffer.length);
// int dataSize = totalSize - 4;
byte[] oleLabel = new byte[8];
System.arraycopy(dataBuffer, 0, oleLabel, 0, Math.min(dataBuffer.length, 8));
label = "ole-"+ HexDump.toHex(oleLabel);
fileName = label;
command = label;
} else {
flags1 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
int len = getStringLength(data, ofs);
label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
len = getStringLength(data, ofs);
fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
flags2 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
unknown1 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;

len = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;

command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
if (totalSize < ofs) {
throw new Ole10NativeException("Invalid Ole10Native");
}

int dataSize = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;

if (dataSize < 0 || totalSize - (ofs - LittleEndianConsts.INT_SIZE) < dataSize) {
throw new Ole10NativeException("Invalid Ole10Native");
}
dataBuffer = new byte[dataSize];
System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
ofs += dataSize;
}
}

/*
* Helper - determine length of zero terminated string (ASCIIZ).
*/
private static int getStringLength(byte[] data, int ofs) {
int len = 0;
while (len+ofs<data.length && data[ofs + len] != 0) {
len++;
/**
* Returns flags1 - currently unknown - usually 0x0002.
*
* @return the flags1
*/
public short getFlags1() {
return flags1;
}
len++;
return len;
}
/**
* Returns the value of the totalSize field - the total length of the structure
* is totalSize + 4 (value of this field + size of this field).
*
* @return the totalSize
*/
public int getTotalSize() {
return totalSize;
}
/**
* Returns the label field - usually the name of the file (without
* directory) but probably may be any name specified during
* packaging/embedding the data.
*
* @return the label
*/
public String getLabel() {
return label;
}
/**
* Returns flags1 - currently unknown - usually 0x0002.
*
* @return the flags1
*/
public short getFlags1() {
return flags1;
}
/**
* Returns the fileName field - usually the name of the file being embedded
* including the full path.
*
* @return the fileName
*/
public String getFileName() {
return fileName;
}
/**
* Returns the label field - usually the name of the file (without directory) but
* probably may be any name specified during packaging/embedding the data.
*
* @return the label
*/
public String getLabel() {
return label;
}
/**
* Returns flags2 - currently unknown - mostly 0x0000.
*
* @return the flags2
*/
public short getFlags2() {
return flags2;
}
/**
* Returns the fileName field - usually the name of the file being embedded
* including the full path.
*
* @return the fileName
*/
public String getFileName() {
return fileName;
}
/**
* Returns unknown1 field - currently unknown.
*
* @return the unknown1
*/
public short getUnknown1() {
return unknown1;
}
/**
* Returns flags2 - currently unknown - mostly 0x0000.
*
* @return the flags2
*/
public short getFlags2() {
return flags2;
}
/**
* Returns the command field - usually the name of the file being embedded
* including the full path, may be a command specified during embedding the
* file.
*
* @return the command
*/
public String getCommand() {
return command;
}
/**
* Returns unknown1 field - currently unknown.
*
* @return the unknown1
*/
public short getUnknown1() {
return unknown1;
}

/**
* Returns the command field - usually the name of the file being embedded
* including the full path, may be a command specified during embedding the file.
*
* @return the command
*/
public String getCommand() {
return command;
}
/**
* Returns the size of the embedded file. If the size is 0 (zero), no data
* has been embedded. To be sure, that no data has been embedded, check
* whether {@link #getDataBuffer()} returns <code>null</code>.
*
* @return the dataSize
*/
public int getDataSize() {
return dataBuffer.length;
}
/**
* Returns the size of the embedded file. If the size is 0 (zero), no data has been
* embedded. To be sure, that no data has been embedded, check whether
* {@link #getDataBuffer()} returns <code>null</code>.
*
* @return the dataSize
*/
public int getDataSize() {
return dataBuffer.length;
}

/**
* Returns the buffer containing the embedded file's data, or <code>null</code>
* if no data was embedded. Note that an embedding may provide information about
* the data, but the actual data is not included. (So label, filename etc. are
* available, but this method returns <code>null</code>.)
*
* @return the dataBuffer
*/
public byte[] getDataBuffer() {
return dataBuffer;
}
/**
* Returns the buffer containing the embedded file's data, or
* <code>null</code> if no data was embedded. Note that an embedding may
* provide information about the data, but the actual data is not included.
* (So label, filename etc. are available, but this method returns
* <code>null</code>.)
*
* @return the dataBuffer
*/
public byte[] getDataBuffer() {
return dataBuffer;
}
/**
* Returns the flags3 - currently unknown.
*
* @return the flags3
*/
public short getFlags3() {
return flags3;
}

/**
* Have the contents printer out into an OutputStream, used when writing a
* file back out to disk (Normally, atom classes will keep their bytes
* around, but non atom classes will just request the bytes from their
* children, then chuck on their header and return)
*/
public void writeOut(OutputStream out) throws IOException {
byte intbuf[] = new byte[LittleEndianConsts.INT_SIZE];
byte shortbuf[] = new byte[LittleEndianConsts.SHORT_SIZE];

ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(intbuf); // total size, will be determined later ..

LittleEndian.putShort(shortbuf, 0, getFlags1());
bos.write(shortbuf);

bos.write(getLabel().getBytes(ISO1));
bos.write(0);

bos.write(getFileName().getBytes(ISO1));
bos.write(0);

LittleEndian.putShort(shortbuf, 0, getFlags2());
bos.write(shortbuf);

LittleEndian.putShort(shortbuf, 0, getUnknown1());
bos.write(shortbuf);

LittleEndian.putInt(intbuf, 0, getCommand().length()+1);
bos.write(intbuf);

bos.write(getCommand().getBytes(ISO1));
bos.write(0);

LittleEndian.putInt(intbuf, 0, getDataBuffer().length);
bos.write(intbuf);

bos.write(getDataBuffer());

LittleEndian.putShort(shortbuf, 0, getFlags3());
bos.write(shortbuf);

// update total size - length of length-field (4 bytes)
byte data[] = bos.toByteArray();
totalSize = data.length - LittleEndianConsts.INT_SIZE;
LittleEndian.putInt(data, 0, totalSize);

out.write(data);
}

public void setFlags1(short flags1) {
this.flags1 = flags1;
}

public void setFlags2(short flags2) {
this.flags2 = flags2;
}

public void setFlags3(short flags3) {
this.flags3 = flags3;
}

public void setLabel(String label) {
this.label = label;
}

public void setFileName(String fileName) {
this.fileName = fileName;
}

public void setCommand(String command) {
this.command = command;
}

public void setUnknown1(short unknown1) {
this.unknown1 = unknown1;
}
/**
* Returns the flags3 - currently unknown.
*
* @return the flags3
*/
public short getFlags3() {
return flags3;
}
/**
* Have the contents printer out into an OutputStream, used when writing a
* file back out to disk (Normally, atom classes will keep their bytes
* around, but non atom classes will just request the bytes from their
* children, then chuck on their header and return)
*/
public void writeOut(OutputStream out) throws IOException {
// byte intbuf[] = new byte[LittleEndianConsts.INT_SIZE];
// byte shortbuf[] = new byte[LittleEndianConsts.SHORT_SIZE];
@SuppressWarnings("resource")
LittleEndianOutputStream leosOut = new LittleEndianOutputStream(out);
switch (mode) {
case parsed: {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);
// total size, will be determined later ..
leos.writeShort(getFlags1());
leos.write(getLabel().getBytes(ISO1));
leos.write(0);
leos.write(getFileName().getBytes(ISO1));
leos.write(0);
leos.writeShort(getFlags2());
leos.writeShort(getUnknown1());
leos.writeInt(getCommand().length() + 1);
leos.write(getCommand().getBytes(ISO1));
leos.write(0);
leos.writeInt(getDataSize());
leos.write(getDataBuffer());
leos.writeShort(getFlags3());
leos.close(); // satisfy compiler ...
leosOut.writeInt(bos.size()); // total size
bos.writeTo(out);
break;
}
case compact:
leosOut.writeInt(getDataSize()+LittleEndianConsts.SHORT_SIZE);
leosOut.writeShort(getFlags1());
out.write(getDataBuffer());
break;
default:
case unparsed:
leosOut.writeInt(getDataSize());
out.write(getDataBuffer());
break;
}
}

public void setDataBuffer(byte dataBuffer[]) {
this.dataBuffer = dataBuffer;
}
public void setFlags1(short flags1) {
this.flags1 = flags1;
}
public void setFlags2(short flags2) {
this.flags2 = flags2;
}
public void setFlags3(short flags3) {
this.flags3 = flags3;
}
public void setLabel(String label) {
this.label = label;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public void setCommand(String command) {
this.command = command;
}
public void setUnknown1(short unknown1) {
this.unknown1 = unknown1;
}
public void setDataBuffer(byte dataBuffer[]) {
this.dataBuffer = dataBuffer;
}
}

+ 11
- 14
src/testcases/org/apache/poi/poifs/AllPOIFSTests.java View File

@@ -17,27 +17,24 @@

package org.apache.poi.poifs;

import junit.framework.Test;
import junit.framework.TestSuite;

import org.apache.poi.poifs.eventfilesystem.TestPOIFSReaderRegistry;
import org.apache.poi.poifs.filesystem.AllPOIFSFileSystemTests;
import org.apache.poi.poifs.nio.TestDataSource;
import org.apache.poi.poifs.property.AllPOIFSPropertyTests;
import org.apache.poi.poifs.storage.AllPOIFSStorageTests;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

/**
* Test suite for all sub-packages of org.apache.poi.poifs
*
* @author Josh Micich
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestPOIFSReaderRegistry.class
, TestDataSource.class
, AllPOIFSFileSystemTests.class
, AllPOIFSPropertyTests.class
, AllPOIFSStorageTests.class
})
public final class AllPOIFSTests {
public static Test suite() {
TestSuite result = new TestSuite("Tests for org.apache.poi.poifs");
result.addTestSuite(TestPOIFSReaderRegistry.class);
result.addTestSuite(TestDataSource.class);
result.addTest(AllPOIFSFileSystemTests.suite());
result.addTest(AllPOIFSPropertyTests.suite());
result.addTest(AllPOIFSStorageTests.suite());
return result;
}
}

+ 18
- 22
src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java View File

@@ -17,31 +17,27 @@

package org.apache.poi.poifs.filesystem;

import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

/**
* Tests for org.apache.poi.poifs.filesystem<br/>
*
* @author Josh Micich
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestDirectoryNode.class
, TestDocument.class
, TestDocumentDescriptor.class
, TestDocumentInputStream.class
, TestDocumentNode.class
, TestDocumentOutputStream.class
, TestEmptyDocument.class
, TestOffice2007XMLException.class
, TestPOIFSDocumentPath.class
, TestPOIFSFileSystem.class
, TestNPOIFSFileSystem.class
, TestPropertySorter.class
, TestOle10Native.class
})
public final class AllPOIFSFileSystemTests {

public static Test suite() {
TestSuite result = new TestSuite("Tests for org.apache.poi.poifs.filesystem");
result.addTestSuite(TestDirectoryNode.class);
result.addTestSuite(TestDocument.class);
result.addTestSuite(TestDocumentDescriptor.class);
result.addTestSuite(TestDocumentInputStream.class);
result.addTestSuite(TestDocumentNode.class);
result.addTestSuite(TestDocumentOutputStream.class);
result.addTestSuite(TestEmptyDocument.class);
result.addTestSuite(TestOffice2007XMLException.class);
result.addTestSuite(TestPOIFSDocumentPath.class);
result.addTestSuite(TestPOIFSFileSystem.class);
result.addTestSuite(TestNPOIFSFileSystem.class);
result.addTestSuite(TestPropertySorter.class);
result.addTestSuite(TestOle10Native.class);
return result;
}
}

+ 77
- 3
src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java View File

@@ -17,14 +17,26 @@

package org.apache.poi.poifs.filesystem;

import junit.framework.TestCase;
import org.apache.poi.POIDataSamples;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.POIDataSamples;
import org.apache.poi.util.IOUtils;
import org.junit.Test;

public class TestOle10Native extends TestCase {
public class TestOle10Native {
private static final POIDataSamples dataSamples = POIDataSamples.getPOIFSInstance();

@Test
public void testOleNative() throws IOException, Ole10NativeException {
POIFSFileSystem fs = new POIFSFileSystem(dataSamples.openResourceAsStream("oleObject1.bin"));

@@ -33,4 +45,66 @@ public class TestOle10Native extends TestCase {
assertEquals("File1.svg", ole.getLabel());
assertEquals("D:\\Documents and Settings\\rsc\\My Documents\\file1.svg", ole.getCommand());
}

@Test
public void testFiles() throws IOException, Ole10NativeException {
File files[] = {
// bug 51891
POIDataSamples.getPOIFSInstance().getFile("multimedia.doc"),
// tika bug 1072
POIDataSamples.getPOIFSInstance().getFile("20-Force-on-a-current-S00.doc"),
// other files containing ole10native records ...
POIDataSamples.getDocumentInstance().getFile("Bug53380_3.doc"),
POIDataSamples.getDocumentInstance().getFile("Bug47731.doc")
};
for (File f : files) {
NPOIFSFileSystem fs = new NPOIFSFileSystem(f, true);
List<Entry> entries = new ArrayList<Entry>();
findOle10(entries, fs.getRoot(), "/", "");
for (Entry e : entries) {
ByteArrayOutputStream bosExp = new ByteArrayOutputStream();
InputStream is = ((DirectoryNode)e.getParent()).createDocumentInputStream(e);
IOUtils.copy(is,bosExp);
is.close();
Ole10Native ole = Ole10Native.createFromEmbeddedOleObject((DirectoryNode)e.getParent());
ByteArrayOutputStream bosAct = new ByteArrayOutputStream();
ole.writeOut(bosAct);
assertThat(bosExp.toByteArray(), equalTo(bosAct.toByteArray()));
}
fs.close();
}
}

/*
void searchOle10Files() throws Exception {
File dir = new File("test-data/document");
for (File file : dir.listFiles(new FileFilter(){
public boolean accept(File pathname) {
return pathname.getName().endsWith("doc");
}
})) {
NPOIFSFileSystem fs = new NPOIFSFileSystem(file, true);
findOle10(null, fs.getRoot(), "/", file.getName());
fs.close();
}
}*/
void findOle10(List<Entry> entries, DirectoryNode dn, String path, String filename) {
Iterator<Entry> iter = dn.getEntries();
while (iter.hasNext()) {
Entry e = iter.next();
if (Ole10Native.OLE10_NATIVE.equals(e.getName())) {
if (entries != null) entries.add(e);
// System.out.println(filename+" : "+path);
} else if (e.isDirectoryEntry()) {
findOle10(entries, (DirectoryNode)e, path+e.getName()+"/", filename);
}
}
}
}

BIN
test-data/poifs/20-Force-on-a-current-S00.doc View File


BIN
test-data/poifs/multimedia.doc View File


Loading…
Cancel
Save