diff --git a/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java b/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java new file mode 100644 index 0000000000..3b2ff76a57 --- /dev/null +++ b/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java @@ -0,0 +1,259 @@ +package org.apache.poi.poifs.filesystem; + +import org.apache.poi.util.*; + +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; + +/** + * Represents an Ole10Native record which is wrapped around certain binary + * files being embedded in OLE2 documents. + * + * @author Rainer Schwarze + */ +public class Ole10Native { + // (the fields as they appear in the raw record:) + private final int totalSize; // 4 bytes, total size of record not including this field + private short flags1; // 2 bytes, unknown, mostly [02 00] + private final String label; // ASCIIZ, stored in this field without the terminating zero + private final String fileName; // ASCIIZ, stored in this field without the terminating zero + private short flags2; // 2 bytes, unknown, mostly [00 00] + // private byte unknown1Length; // 1 byte, specifying the length of the following byte array (unknown1) + private byte[] unknown1; // see below + private byte[] unknown2; // 3 bytes, unknown, mostly [00 00 00] + private final String command; // ASCIIZ, stored in this field without the terminating zero + private final int dataSize; // 4 bytes (if space), size of following buffer + private final byte[] dataBuffer; // varying size, the actual native data + private short flags3; // some final flags? or zero terminators?, sometimes not there + public static final String OLE10_NATIVE = "\u0001Ole10Native"; + + /** + * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected + * to include a stream "{01}Ole10Native" 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 { + boolean plain = false; + + try { + poifs.getRoot().getEntry("\u0001Ole10ItemName"); + plain = true; + } catch (FileNotFoundException ex) { + plain = false; + } + + DocumentInputStream dis = poifs.createDocumentInputStream(OLE10_NATIVE); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + IOUtils.copy(dis, bos); + byte[] data = bos.toByteArray(); + + return new Ole10Native(data, 0, plain); + } + + /** + * 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 + + if (data.length LittleEndianConsts.INT_SIZE) { + dataSize = LittleEndian.getInt(data, ofs); + ofs += LittleEndianConsts.INT_SIZE; + + if (dataSize > totalSize || dataSize<0) { + throw new Ole10NativeException("Invalid Ole10Native"); + } + + dataBuffer = new byte[dataSize]; + System.arraycopy(data, ofs, dataBuffer, 0, dataSize); + ofs += dataSize; + + if (unknown1.length > 0) { + flags3 = LittleEndian.getShort(data, ofs); + ofs += LittleEndianConsts.SHORT_SIZE; + } else { + flags3 = 0; + } + } else { + throw new Ole10NativeException("Invalid Ole10Native"); + } + } + } + + /* + * Helper - determine length of zero terminated string (ASCIIZ). + */ + private static int getStringLength(byte[] data, int ofs) { + int len = 0; + while (len+ofsnull. + * + * @return the dataSize + */ + public int getDataSize() { + return dataSize; + } + + /** + * Returns the buffer containing the embedded file's data, or null + * 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 null.) + * + * @return the dataBuffer + */ + public byte[] getDataBuffer() { + return dataBuffer; + } + + /** + * Returns the flags3 - currently unknown. + * + * @return the flags3 + */ + public short getFlags3() { + return flags3; + } +} diff --git a/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java b/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java new file mode 100644 index 0000000000..d3c36ea12d --- /dev/null +++ b/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java @@ -0,0 +1,7 @@ +package org.apache.poi.poifs.filesystem; + +public class Ole10NativeException extends Exception { + public Ole10NativeException(String message) { + super(message); + } +} diff --git a/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java b/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java index 9c8f6acd74..295b5ad574 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java @@ -40,6 +40,7 @@ public final class AllPOIFSFileSystemTests { result.addTestSuite(TestPOIFSDocumentPath.class); result.addTestSuite(TestPOIFSFileSystem.class); result.addTestSuite(TestPropertySorter.class); + result.addTestSuite(TestOle10Native.class); return result; } } diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java b/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java new file mode 100644 index 0000000000..332cdaba6d --- /dev/null +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java @@ -0,0 +1,19 @@ +package org.apache.poi.poifs.filesystem; + +import junit.framework.TestCase; +import org.apache.poi.POIDataSamples; + +import java.io.IOException; + +public class TestOle10Native extends TestCase { + private static final POIDataSamples dataSamples = POIDataSamples.getPOIFSInstance(); + + public void testOleNative() throws IOException, Ole10NativeException { + POIFSFileSystem fs = new POIFSFileSystem(dataSamples.openResourceAsStream("oleObject1.bin")); + + Ole10Native ole = Ole10Native.createFromEmbeddedOleObject(fs); + + assertEquals("File1.svg", ole.getLabel()); + assertEquals("D:\\Documents and Settings\\rsc\\My Documents\\file1.svg", ole.getCommand()); + } +} diff --git a/test-data/poifs/oleObject1.bin b/test-data/poifs/oleObject1.bin new file mode 100644 index 0000000000..fc46302968 Binary files /dev/null and b/test-data/poifs/oleObject1.bin differ