From 1e25322d850bc3bf562d4a479e6fea84db76adb7 Mon Sep 17 00:00:00 2001 From: Maxim Valyanskiy Date: Thu, 9 Sep 2010 13:18:48 +0000 Subject: [PATCH] Add code for reading Ole10Native data git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@995415 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/poifs/filesystem/Ole10Native.java | 259 ++++++++++++++++++ .../filesystem/Ole10NativeException.java | 7 + .../filesystem/AllPOIFSFileSystemTests.java | 1 + .../poi/poifs/filesystem/TestOle10Native.java | 19 ++ test-data/poifs/oleObject1.bin | Bin 0 -> 14336 bytes 5 files changed, 286 insertions(+) create mode 100644 src/java/org/apache/poi/poifs/filesystem/Ole10Native.java create mode 100644 src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java create mode 100644 src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java create mode 100644 test-data/poifs/oleObject1.bin 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 000000000..3b2ff76a5 --- /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 000000000..d3c36ea12 --- /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 9c8f6acd7..295b5ad57 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 000000000..332cdaba6 --- /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 0000000000000000000000000000000000000000..fc463029680e547c6f945e512a101d1d5c5e2cab GIT binary patch literal 14336 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 literal 0 HcmV?d00001