You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2020/06/11 00:43:45 UTC

svn commit: r1878730 - in /poi: site/src/documentation/content/xdocs/ trunk/src/examples/src/org/apache/poi/hpsf/examples/ trunk/src/java/org/apache/poi/poifs/eventfilesystem/ trunk/src/java/org/apache/poi/poifs/filesystem/ trunk/src/java/org/apache/po...

Author: kiwiwings
Date: Thu Jun 11 00:43:45 2020
New Revision: 1878730

URL: http://svn.apache.org/viewvc?rev=1878730&view=rev
Log:
64512 - Ole10Native aka embedded / object packager - handle UTF16 variants

Added:
    poi/trunk/test-data/spreadsheet/bug64512_embed.xlsx   (with props)
Modified:
    poi/site/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java
    poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java
    poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderEvent.java
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java
    poi/trunk/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java
    poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java

Modified: poi/site/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/changes.xml?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/changes.xml (original)
+++ poi/site/src/documentation/content/xdocs/changes.xml Thu Jun 11 00:43:45 2020
@@ -102,6 +102,7 @@
             <action type="add" fixes-bug="63819" context="SS_Common">Support DateValue function</action>
             <action type="add" fixes-bug="github-179" context="SS_Common">Add an option for RangeCopier.copyRange() also clone styles</action>
             <action type="fix" fixes-bug="63290" context="XSLF">Retrieve default run properties from paragraph</action>
+            <action type="add" fixes-bug="64512" context="POIFS">Ole10Native aka embedded / object packager - handle UTF16 variants</action>
         </actions>
     </release>
 

Modified: poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java (original)
+++ poi/trunk/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java Thu Jun 11 00:43:45 2020
@@ -163,10 +163,20 @@ public final class CopyCompare {
                 // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
                 // Get the root directory. It does not have to be created since it always exists in a POIFS.
                 DirectoryEntry de = poiFs.getRoot();
+                if ("/".equals(path.toString())) {
+                    de.setStorageClsid(event.getStorageClassId());
+                }
 
                 for (int i=0; i<path.length(); i++) {
                     String subDir = path.getComponent(i);
-                    de = (de.hasEntry(subDir)) ? (DirectoryEntry)de.getEntry(subDir) : de.createDirectory(subDir);
+                    if (de.hasEntry(subDir)) {
+                        de = (DirectoryEntry)de.getEntry(subDir);
+                    } else {
+                        de = de.createDirectory(subDir);
+                        if (i == path.length()-1) {
+                            de.setStorageClsid(event.getStorageClassId());
+                        }
+                    }
                 }
 
                 if (event.getName() != null) {

Modified: poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java Thu Jun 11 00:43:45 2020
@@ -15,7 +15,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
+
 
 package org.apache.poi.poifs.eventfilesystem;
 
@@ -25,12 +25,12 @@ import java.io.InputStream;
 
 import org.apache.poi.poifs.filesystem.DocumentInputStream;
 import org.apache.poi.poifs.filesystem.POIFSDocument;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.poifs.property.DirectoryProperty;
 import org.apache.poi.poifs.property.DocumentProperty;
-import org.apache.poi.poifs.property.PropertyTable;
 import org.apache.poi.poifs.property.Property;
+import org.apache.poi.poifs.property.PropertyTable;
 import org.apache.poi.poifs.property.RootProperty;
 import org.apache.poi.util.IOUtils;
 
@@ -228,7 +228,7 @@ public class POIFSReader
                         document = new POIFSDocument((DocumentProperty)property, poifs);
                     }
                     try (DocumentInputStream dis = new DocumentInputStream(document)) {
-                        POIFSReaderEvent pe = new POIFSReaderEvent(dis, path, name);
+                        POIFSReaderEvent pe = new POIFSReaderEvent(dis, path, name, dir.getStorageClsid());
                         rl.processPOIFSReaderEvent(pe);
                     }
                 }
@@ -240,7 +240,7 @@ public class POIFSReader
         }
 
         for (POIFSReaderListener rl : registry.getListeners(path, ".")) {
-            POIFSReaderEvent pe = new POIFSReaderEvent(null, path, null);
+            POIFSReaderEvent pe = new POIFSReaderEvent(null, path, null, dir.getStorageClsid());
             rl.processPOIFSReaderEvent(pe);
         }
     }

Modified: poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderEvent.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderEvent.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderEvent.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderEvent.java Thu Jun 11 00:43:45 2020
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -15,67 +14,63 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.eventfilesystem;
 
+import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.poifs.filesystem.DocumentInputStream;
 import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
 
 /**
  * Class POIFSReaderEvent
- *
- * @author Marc Johnson (mjohnson at apache dot org)
- * @version %I%, %G%
  */
 
-public class POIFSReaderEvent
-{
+public class POIFSReaderEvent {
     private final DocumentInputStream stream;
-    private final POIFSDocumentPath   path;
-    private final String              documentName;
+    private final POIFSDocumentPath path;
+    private final String documentName;
+    private final ClassID storageClassId;
 
     /**
      * package scoped constructor
      *
-     * @param stream the DocumentInputStream, freshly opened
-     * @param path the path of the document
+     * @param stream       the DocumentInputStream, freshly opened
+     * @param path         the path of the document
      * @param documentName the name of the document
      */
-
     POIFSReaderEvent(final DocumentInputStream stream,
-                     final POIFSDocumentPath path, final String documentName)
-    {
-        this.stream       = stream;
-        this.path         = path;
+                     final POIFSDocumentPath path, final String documentName, final ClassID storageClassId) {
+        this.stream = stream;
+        this.path = path;
         this.documentName = documentName;
+        this.storageClassId = storageClassId;
     }
 
     /**
      * @return the DocumentInputStream, freshly opened
      */
-
-    public DocumentInputStream getStream()
-    {
+    public DocumentInputStream getStream() {
         return stream;
     }
 
     /**
      * @return the document's path
      */
-
-    public POIFSDocumentPath getPath()
-    {
+    public POIFSDocumentPath getPath() {
         return path;
     }
 
     /**
      * @return the document's name
      */
-
-    public String getName()
-    {
+    public String getName() {
         return documentName;
     }
-}   // end public class POIFSReaderEvent
 
+    /**
+     * @return the storage class id of the path
+     */
+    public ClassID getStorageClassId() {
+        return storageClassId;
+    }
+}
\ No newline at end of file

Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java Thu Jun 11 00:43:45 2020
@@ -60,7 +60,7 @@ public final class EntryUtils {
 
     /**
      * Copies all the nodes from one POIFS Directory to another
-     * 
+     *
      * @param sourceRoot
      *            is the source Directory to copy from
      * @param targetRoot
@@ -75,7 +75,7 @@ public final class EntryUtils {
 
     /**
      * Copies all nodes from one POIFS to the other
-     * 
+     *
      * @param source
      *            is the source POIFS to copy from
      * @param target
@@ -85,13 +85,13 @@ public final class EntryUtils {
     throws IOException {
         copyNodes( source.getRoot(), target.getRoot() );
     }
-    
+
     /**
      * Copies nodes from one POIFS to the other, minus the excepts.
      * This delegates the filtering work to {@link FilteringDirectoryNode},
      *  so excepts can be of the form "NodeToExclude" or
      *  "FilteringDirectory/ExcludedChildNode"
-     * 
+     *
      * @param source is the source POIFS to copy from
      * @param target is the target POIFS to copy to
      * @param excepts is a list of Entry Names to be excluded from the copy
@@ -103,19 +103,23 @@ public final class EntryUtils {
               new FilteringDirectoryNode(target.getRoot(), excepts)
         );
     }
-    
+
     /**
      * Checks to see if the two Directories hold the same contents.
-     * For this to be true, they must have entries with the same names,
-     *  no entries in one but not the other, and the size+contents
-     *  of each entry must match, and they must share names.
+     * For this to be true ...
+     * <ul>
+     *     <li>they must have entries with the same names</li>
+     *     <li>no entries in one but not the other</li>
+     *     <li>the size+contents of each entry must match</li>
+     *     <li>the storage classid of the directories must match</li>
+     * </ul>
      * To exclude certain parts of the Directory from being checked,
      *  use a {@link FilteringDirectoryNode}
      */
     public static boolean areDirectoriesIdentical(DirectoryEntry dirA, DirectoryEntry dirB) {
         return new DirectoryDelegate(dirA).equals(new DirectoryDelegate(dirB));
     }
-    
+
     /**
      * Compares two {@link DocumentEntry} instances of a POI file system.
      * Documents that are not property set streams must be bitwise identical.
@@ -185,6 +189,10 @@ public final class EntryUtils {
                 return false;
             }
 
+            if (!dir.getStorageClsid().equals(dd.dir.getStorageClsid())) {
+                return false;
+            }
+
             return entries().equals(dd.entries());
         }
     }

Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java Thu Jun 11 00:43:45 2020
@@ -21,44 +21,69 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutputStream;
 import org.apache.poi.util.StringUtil;
 
 /**
  * Represents an Ole10Native record which is wrapped around certain binary
- * files being embedded in OLE2 documents.
+ * files being embedded in OLE2 documents.<p>
+ *
+ * Ole10Native objects come in different shapes:
+ * <ul>
+ *     <li>unparsed: we can't identify it's structure</li>
+ *     <li>compact: same as unparsed but with a leading flag</li>
+ *     <li>parsed - Ole-Class "Package": data + ASCII label,command,filename</li>
+ *     <li>parsed - Ole-Class "Package2": as above plus UTF16 label,command,filename</li>
+ * </ul>
  */
+@SuppressWarnings("unused")
 public class Ole10Native {
 
 
     public static final String OLE10_NATIVE = "\u0001Ole10Native";
-    protected static final String ISO1 = "ISO-8859-1";
-    //arbitrarily selected; may need to increase
+    private static final Charset ISO1 = StandardCharsets.ISO_8859_1;
+    // arbitrarily selected; may need to increase
     private static final int MAX_RECORD_LENGTH = 100_000_000;
+    // arbitrarily selected; may need to increase
+    private static final int MAX_STRING_LENGTH = 1024;
 
     /**
      * Default content of the \u0001Ole entry
      */
     private static final byte[] OLE_MARKER_BYTES =
-        { 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+            {1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     private static final String OLE_MARKER_NAME = "\u0001Ole";
 
 
-
-    // (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;          // 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;          // some final flags? or zero terminators?, sometimes not there
+    // 4 bytes, total size of record not including this field
+    private int totalSize;
+    // 2 bytes, unknown, mostly [02 00]
+    private short flags1 = 2;
+    // ASCIIZ, stored in this field without the terminating zero
+    private String label;
+    // ASCIIZ, stored in this field without the terminating zero
+    private String fileName;
+    // 2 bytes, unknown, mostly [00 00]
+    private short flags2;
+    // see below
+    private short unknown1 = 3;
+    // ASCIIZ, stored in this field without the terminating zero
+    private String command;
+    // varying size, the actual native data
+    private byte[] dataBuffer;
+    // UTF16-LE String with leading length
+    private String command2;
+    // UTF16-LE String with leading length
+    private String label2;
+    // UTF16-LE String with leading length
+    private String fileName2;
 
     /**
      * the field encoding mode - merely a try-and-error guess ...
@@ -81,7 +106,6 @@ public class Ole10Native {
     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
@@ -89,11 +113,11 @@ public class Ole10Native {
      *
      * @param poifs POI Filesystem object
      * @return Returns an instance of this class
-     * @throws IOException on IO error
+     * @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());
+        return createFromEmbeddedOleObject(poifs.getRoot());
     }
 
     /**
@@ -103,26 +127,27 @@ public class Ole10Native {
      *
      * @param directory POI Filesystem object
      * @return Returns an instance of this class
-     * @throws IOException on IO error
+     * @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);
-       try (DocumentInputStream dis = directory.createDocumentInputStream(nativeEntry)) {
-           byte[] data = IOUtils.toByteArray(dis, nativeEntry.getSize(), MAX_RECORD_LENGTH);
-           return new Ole10Native(data, 0);
-       }
+        DocumentEntry nativeEntry = (DocumentEntry) directory.getEntry(OLE10_NATIVE);
+        try (DocumentInputStream dis = directory.createDocumentInputStream(nativeEntry)) {
+            byte[] data = IOUtils.toByteArray(dis, nativeEntry.getSize(), MAX_RECORD_LENGTH);
+            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;
+        setLabel(label);
+        setFileName(filename);
+        setCommand(command);
+        command2 = command;
+        setDataBuffer(data);
+        mode = EncodingMode.parsed;
     }
 
     /**
@@ -132,81 +157,64 @@ public class Ole10Native {
      * @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
+    public Ole10Native(final byte[] data, final int offset) throws Ole10NativeException {
+        LittleEndianByteArrayInputStream leis = new LittleEndianByteArrayInputStream(data, offset);
 
-        if (data.length < offset + 2) {
-            throw new Ole10NativeException("data is too small");
-        }
+        totalSize = leis.readInt();
+        leis.limit(totalSize + LittleEndianConsts.INT_SIZE);
 
-        totalSize = LittleEndian.getInt(data, ofs);
-        ofs += LittleEndianConsts.INT_SIZE;
+        leis.mark(0);
 
-        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;
+        try {
+            flags1 = leis.readShort();
+            if (flags1 == 2) {
+                leis.mark(0);
+                // some files like equations don't have a valid filename,
+                // but somehow encode the formula right away in the ole10 header
+                boolean validFileName = !Character.isISOControl(leis.readByte());
+                leis.reset();
+
+                if (validFileName) {
+                    readParsed(leis);
+                } else {
+                    readCompact(leis);
+                }
             } else {
-                mode = EncodingMode.parsed;
+                leis.reset();
+                readUnparsed(leis);
             }
+        } catch (IOException e) {
+            throw new Ole10NativeException("Invalid Ole10Native", e);
         }
+    }
 
-        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;
+    private void readParsed(LittleEndianByteArrayInputStream leis) throws Ole10NativeException, IOException {
+        mode = EncodingMode.parsed;
+        label = readAsciiZ(leis);
+        fileName = readAsciiZ(leis);
+        flags2 = leis.readShort();
+        unknown1 = leis.readShort();
+        command = readAsciiLen(leis);
+        dataBuffer = IOUtils.toByteArray(leis, leis.readInt(), MAX_RECORD_LENGTH);
+
+        leis.mark(0);
+        short lowSize = leis.readShort();
+        if (lowSize != 0) {
+            leis.reset();
+            command2 = readUtf16(leis);
+            label2 = readUtf16(leis);
+            fileName2 = readUtf16(leis);
         }
+    }
 
-        if ((long)dataSize + (long)ofs > (long)data.length) { //cast to avoid overflow
-            throw new Ole10NativeException("Invalid Ole10Native: declared data length > available data");
-        }
-        dataBuffer = IOUtils.safelyClone(data, ofs, dataSize, MAX_RECORD_LENGTH);
+    private void readCompact(LittleEndianByteArrayInputStream leis) throws IOException {
+        mode = EncodingMode.compact;
+        dataBuffer = IOUtils.toByteArray(leis, totalSize - LittleEndianConsts.SHORT_SIZE, MAX_RECORD_LENGTH);
+    }
+
+    private void readUnparsed(LittleEndianByteArrayInputStream leis) throws IOException {
+        mode = EncodingMode.unparsed;
+        dataBuffer = IOUtils.toByteArray(leis, totalSize, MAX_RECORD_LENGTH);
     }
 
     /**
@@ -230,16 +238,30 @@ public class Ole10Native {
     }
 
 
-    /*
-     * Helper - determine length of zero terminated string (ASCIIZ).
+    /**
+     * Read 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++;
+    private static String readAsciiZ(LittleEndianInput is) throws Ole10NativeException {
+        // arbitrary sized buffer - not sure how big strings can get in an Ole10 record
+        byte[] buf = new byte[MAX_STRING_LENGTH];
+        for (int i=0; i<buf.length; i++) {
+            if ((buf[i] = is.readByte()) == 0) {
+                return StringUtil.getFromCompressedUnicode(buf, 0, i);
+            }
         }
-        len++;
-        return len;
+        throw new Ole10NativeException("AsciiZ string was not null terminated after " + MAX_STRING_LENGTH + " bytes - Exiting.");
+    }
+
+    private static String readAsciiLen(LittleEndianByteArrayInputStream leis) throws IOException {
+        int size = leis.readInt();
+        byte[] buf = IOUtils.toByteArray(leis, size, MAX_STRING_LENGTH);
+        return (buf.length == 0) ? "" : StringUtil.getFromCompressedUnicode(buf, 0, size - 1);
+    }
+
+    private static String readUtf16(LittleEndianByteArrayInputStream leis) throws IOException {
+        int size = leis.readInt();
+        byte[] buf = IOUtils.toByteArray(leis, size * 2, MAX_STRING_LENGTH);
+        return StringUtil.getFromUnicodeLE(buf, 0, size);
     }
 
     /**
@@ -336,15 +358,6 @@ public class Ole10Native {
     }
 
     /**
-     * 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
@@ -358,40 +371,53 @@ public class Ole10Native {
         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;
+            case parsed: {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                try (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());
+
+                    if (command2 == null || label2 == null || fileName2 == null) {
+                        leos.writeShort(0);
+                    } else {
+                        leos.writeUInt(command2.length());
+                        leos.write(StringUtil.getToUnicodeLE(command2));
+                        leos.writeUInt(label2.length());
+                        leos.write(StringUtil.getToUnicodeLE(label2));
+                        leos.writeUInt(fileName2.length());
+                        leos.write(StringUtil.getToUnicodeLE(fileName2));
+                    }
+                }
+
+                // total size
+                leosOut.writeInt(bos.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;
         }
 
     }
@@ -404,10 +430,6 @@ public class Ole10Native {
         this.flags2 = flags2;
     }
 
-    public void setFlags3(short flags3) {
-        this.flags3 = flags3;
-    }
-
     public void setLabel(String label) {
         this.label = label;
     }
@@ -427,4 +449,46 @@ public class Ole10Native {
     public void setDataBuffer(byte[] dataBuffer) {
         this.dataBuffer = dataBuffer.clone();
     }
+
+    /**
+     * Get Command string of UTF16 extended OLE packages or {@code null} if not set or not UTF16 extended
+     */
+    public String getCommand2() {
+        return command2;
+    }
+
+    /**
+     * Set Command string for UTF16 extended OLE packages or {@code null} if not set or not UTF16 extended
+     */
+    public void setCommand2(String command2) {
+        this.command2 = command2;
+    }
+
+    /**
+     * Get Label string for UTF16 extended OLE packages or {@code null} if not set or not UTF16 extended
+     */
+    public String getLabel2() {
+        return label2;
+    }
+
+    /**
+     * Set Label string for UTF16 extended OLE packages or {@code null} if not set or not UTF16 extended
+     */
+    public void setLabel2(String label2) {
+        this.label2 = label2;
+    }
+
+    /**
+     * Get filename string for UTF16 extended OLE packages or {@code null} if not set or not UTF16 extended
+     */
+    public String getFileName2() {
+        return fileName2;
+    }
+
+    /**
+     * Set filename string for UTF16 extended OLE packages or {@code null} if not set or not UTF16 extended
+     */
+    public void setFileName2(String fileName2) {
+        this.fileName2 = fileName2;
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java Thu Jun 11 00:43:45 2020
@@ -21,4 +21,12 @@ public class Ole10NativeException extend
     public Ole10NativeException(String message) {
         super(message);
     }
+
+    public Ole10NativeException(Throwable cause) {
+        super(cause);
+    }
+
+    public Ole10NativeException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java (original)
+++ poi/trunk/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java Thu Jun 11 00:43:45 2020
@@ -91,8 +91,8 @@ public class LittleEndianByteArrayInputS
 	   }
 	   this.pos = pos;
 	}
-	
-	
+
+
 	@Override
     public byte readByte() {
 		checkPosition(1);
@@ -140,14 +140,14 @@ public class LittleEndianByteArrayInputS
 	}
 
 	public long readUInt() {
-	    return readInt() & 0x00FFFFFFFFL; 
+	    return readInt() & 0x00FFFFFFFFL;
     }
 
     @Override
     public double readDouble() {
         return Double.longBitsToDouble(readLong());
     }
-	
+
 	@Override
     public void readFully(byte[] buffer, int off, int len) {
 		checkPosition(len);
@@ -164,4 +164,12 @@ public class LittleEndianByteArrayInputS
     public void readPlain(byte[] buf, int off, int len) {
         readFully(buf, off, len);
     }
+
+	/**
+	 * Change the limit of the ByteArrayInputStream
+	 * @param size the new limit - is truncated to length of internal buffer
+	 */
+	public void limit(int size) {
+		count = Math.min(size, buf.length);
+	}
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java Thu Jun 11 00:43:45 2020
@@ -28,7 +28,6 @@ import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.apache.poi.ooxml.POIXMLDocument;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
@@ -441,14 +440,14 @@ public final class XSSFDrawing extends P
         long shapeId = (sheetIndex + 1L) * 1024 + newShapeId();
 
         // add reference to OLE part
+        final XSSFRelation rel = XSSFRelation.OLEEMBEDDINGS;
         PackagePartName olePN;
         try {
-            olePN = PackagingURIHelper.createPartName("/xl/embeddings/oleObject" + storageId + ".bin");
+            olePN = PackagingURIHelper.createPartName(rel.getFileName(storageId));
         } catch (InvalidFormatException e) {
             throw new POIXMLException(e);
         }
-        PackageRelationship olePR = sheetPart.addRelationship(olePN, TargetMode.INTERNAL,
-            POIXMLDocument.OLE_OBJECT_REL_TYPE);
+        PackageRelationship olePR = sheetPart.addRelationship(olePN, TargetMode.INTERNAL, rel.getRelation());
 
         // add reference to image part
         XSSFPictureData imgPD = sh.getWorkbook().getAllPictures().get(pictureIndex);

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java Thu Jun 11 00:43:45 2020
@@ -247,9 +247,9 @@ public final class XSSFRelation extends
     );
 
     public static final XSSFRelation OLEEMBEDDINGS = new XSSFRelation(
-        null,
+        "application/vnd.openxmlformats-officedocument.oleObject",
         POIXMLDocument.OLE_OBJECT_REL_TYPE,
-        null
+        "/xl/embeddings/oleObject#.bin"
     );
 
     public static final XSSFRelation PACKEMBEDDINGS = new XSSFRelation(

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java Thu Jun 11 00:43:45 2020
@@ -2383,19 +2383,20 @@ public class XSSFWorkbook extends POIXML
     @Override
     public int addOlePackage(byte[] oleData, String label, String fileName, String command)
             throws IOException {
+        final XSSFRelation rel = XSSFRelation.OLEEMBEDDINGS;
+
         // find an unused part name
         OPCPackage opc = getPackage();
         PackagePartName pnOLE;
-        int oleId=0;
-        do {
-            try {
-                pnOLE = PackagingURIHelper.createPartName( "/xl/embeddings/oleObject"+(++oleId)+".bin" );
-            } catch (InvalidFormatException e) {
-                throw new IOException("ole object name not recognized", e);
-            }
-        } while (opc.containPart(pnOLE));
+        int oleId;
+        try {
+            oleId = opc.getUnusedPartIndex(rel.getDefaultFileName());
+            pnOLE = PackagingURIHelper.createPartName(rel.getFileName(oleId));
+        } catch (InvalidFormatException e) {
+            throw new IOException("ole object name not recognized", e);
+        }
 
-        PackagePart pp = opc.createPart( pnOLE, "application/vnd.openxmlformats-officedocument.oleObject" );
+        PackagePart pp = opc.createPart( pnOLE, rel.getContentType() );
 
         Ole10Native ole10 = new Ole10Native(label, fileName, command, oleData);
 

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java Thu Jun 11 00:43:45 2020
@@ -23,16 +23,29 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Locale;
 
+import org.apache.commons.codec.binary.Base64;
 import org.apache.poi.POIDataSamples;
+import org.apache.poi.hpsf.ClassIDPredefined;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.EntryUtils;
+import org.apache.poi.poifs.filesystem.Ole10Native;
+import org.apache.poi.poifs.filesystem.Ole10NativeException;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.sl.usermodel.AutoShape;
 import org.apache.poi.sl.usermodel.ShapeType;
 import org.apache.poi.sl.usermodel.Slide;
@@ -41,20 +54,92 @@ import org.apache.poi.ss.extractor.Embed
 import org.apache.poi.ss.extractor.EmbeddedExtractor;
 import org.apache.poi.xslf.usermodel.XMLSlideShow;
 import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFObjectData;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class TestEmbedOLEPackage {
     private static byte[] samplePPT, samplePPTX, samplePNG;
-    
+
+    private static final POIDataSamples ssamples = POIDataSamples.getSpreadSheetInstance();
+
     @BeforeClass
     public static void init() throws IOException, ReflectiveOperationException {
         samplePPT = getSamplePPT(false);
         samplePPTX = getSamplePPT(true);
-        samplePNG = POIDataSamples.getSpreadSheetInstance().readFile("logoKarmokar4.png");
+        samplePNG = ssamples.readFile("logoKarmokar4.png");
     }
-    
+
+    @Test
+    public void embedPDF() throws IOException {
+        try (InputStream is = ssamples.openResourceAsStream("bug64512_embed.xlsx");
+            XSSFWorkbook wb = new XSSFWorkbook(is)) {
+            List<XSSFObjectData> oleShapes = new ArrayList<>();
+            List<Ole10Native> ole10s = new ArrayList<>();
+            List<String> digests = new ArrayList<>();
+
+            final boolean digestMatch =
+                wb.getSheetAt(0).getDrawingPatriarch().getShapes().stream()
+                .map(s -> (XSSFObjectData)s)
+                .filter(oleShapes::add)
+                .map(TestEmbedOLEPackage::extractOle10Native)
+                .filter(ole10s::add)
+                .map(TestEmbedOLEPackage::digest)
+                .allMatch("FUJBVHTAZ0ly/TNDNmEj1gQ4a2TbZwDMVF4WUkDQLaM="::equals);
+
+            assertEquals(2, oleShapes.size());
+            assertEquals("Package", oleShapes.get(0).getOLE2ClassName());
+            assertEquals("Package2", oleShapes.get(1).getOLE2ClassName());
+            assertTrue(digestMatch);
+
+            final String expLabel = "Apache_POI_project_logo_(2018).pdf";
+            final String expFilenName = "C:\\Dell\\Apache_POI_project_logo_(2018).pdf";
+            final String expCmd1 = "C:\\Users\\KIWIWI~1\\AppData\\Local\\Temp\\{84287F34-B79C-4F3A-9A92-6BB664586F48}\\Apache_POI_project_logo_(2018).pdf";
+            final String expCmd2 = "C:\\Users\\KIWIWI~1\\AppData\\Local\\Temp\\{84287F34-B79C-4F3A-9A92-6BB664586F48}\\Apache_POI_project_logo_(2).pdf";
+
+            assertTrue(ole10s.stream().map(Ole10Native::getLabel).allMatch(expLabel::equals));
+            assertTrue(ole10s.stream().map(Ole10Native::getFileName).allMatch(expFilenName::equals));
+            assertEquals(expCmd1, ole10s.get(0).getCommand());
+            assertEquals(expCmd2, ole10s.get(1).getCommand());
+
+            for (Ole10Native o : ole10s) {
+                assertEquals(o.getLabel(), o.getLabel2());
+                assertEquals(o.getCommand(), o.getCommand2());
+                assertEquals(o.getFileName(), o.getFileName2());
+            }
+
+            Ole10Native scratch = new Ole10Native(expLabel, expFilenName, expCmd1,  ole10s.get(0).getDataBuffer());
+            scratch.setLabel2(expLabel);
+            scratch.setFileName2(expFilenName);
+            scratch.setCommand2(expCmd1);
+
+            try (POIFSFileSystem scratchFS = new POIFSFileSystem();
+                POIFSFileSystem ole1FS = new POIFSFileSystem(new ByteArrayInputStream(oleShapes.get(0).getObjectData()))) {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                scratch.writeOut(bos);
+                scratchFS.createDocument(new ByteArrayInputStream(bos.toByteArray()), Ole10Native.OLE10_NATIVE);
+                scratchFS.getRoot().setStorageClsid(ClassIDPredefined.OLE_V1_PACKAGE.getClassID());
+                assertTrue(EntryUtils.areDirectoriesIdentical(ole1FS.getRoot(), scratchFS.getRoot()));
+            }
+        }
+    }
+
+    private static Ole10Native extractOle10Native(XSSFObjectData objectData) {
+        try (InputStream is = objectData.getObjectPart().getInputStream();
+             POIFSFileSystem poifs = new POIFSFileSystem(is)) {
+            return Ole10Native.createFromEmbeddedOleObject(poifs);
+        } catch (IOException | Ole10NativeException e) {
+            throw new AssertionError(e.getMessage(), e);
+        }
+    }
+
+    private static String digest(Ole10Native ole10) {
+        MessageDigest sha = CryptoFunctions.getMessageDigest(HashAlgorithm.sha256);
+        byte[] digest = sha.digest(ole10.getDataBuffer());
+        return Base64.encodeBase64String(digest);
+    }
+
     @Test
     public void embedXSSF() throws IOException {
         Workbook wb1 = new XSSFWorkbook();
@@ -71,9 +156,9 @@ public class TestEmbedOLEPackage {
     public void embedHSSF() throws IOException {
         assumeFalse(xslfOnly());
 
-        Workbook wb1 = new HSSFWorkbook();
+        HSSFWorkbook wb1 = new HSSFWorkbook();
         addEmbeddedObjects(wb1);
-        Workbook wb2 = HSSFTestDataSamples.writeOutAndReadBack((HSSFWorkbook)wb1);
+        Workbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb1);
         validateEmbeddedObjects(wb2);
 
         wb2.close();
@@ -97,17 +182,17 @@ public class TestEmbedOLEPackage {
             }
         }
     }
-    
+
     static void addEmbeddedObjects(Workbook wb) throws IOException {
         boolean ooxml = wb.getClass().getName().toLowerCase(Locale.ROOT).contains("xssf");
         int picIdx = wb.addPicture(samplePNG, Workbook.PICTURE_TYPE_PNG);
         byte[] data = (ooxml) ? samplePPTX : samplePPT;
         String ext = (ooxml) ? ".pptx" : ".ppt";
-        
+
         int oleIdx1a = wb.addOlePackage(data, "dummy1a"+ext, "dummy1a"+ext, "dummy1a"+ext);
         int oleIdx1b = wb.addOlePackage(data, "dummy1b"+ext, "dummy1b"+ext, "dummy1b"+ext);
         int oleIdx2 = wb.addOlePackage(data, "dummy2"+ext, "dummy2"+ext, "dummy2"+ext);
-        
+
         Sheet sh1 = wb.createSheet();
         Drawing<?> pat1 = sh1.createDrawingPatriarch();
         ClientAnchor anchor1a = pat1.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
@@ -120,7 +205,7 @@ public class TestEmbedOLEPackage {
         ClientAnchor anchor2 = pat2.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
         pat2.createObjectData(anchor2, oleIdx2, picIdx);
     }
-    
+
     static byte[] getSamplePPT(boolean ooxml) throws IOException, ReflectiveOperationException {
         SlideShow<?,?> ppt = (ooxml) ? new XMLSlideShow()
             : (SlideShow<?,?>)Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow").newInstance();

Modified: poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java?rev=1878730&r1=1878729&r2=1878730&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestOle10Native.java Thu Jun 11 00:43:45 2020
@@ -17,11 +17,9 @@
 
 package org.apache.poi.poifs.filesystem;
 
-import static org.apache.poi.POITestCase.assertContains;
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -33,11 +31,17 @@ import java.util.List;
 
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.RecordFormatException;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class TestOle10Native {
     private static final POIDataSamples dataSamples = POIDataSamples.getPOIFSInstance();
 
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
     @Test
     public void testOleNative() throws IOException, Ole10NativeException {
         POIFSFileSystem fs = new POIFSFileSystem(dataSamples.openResourceAsStream("oleObject1.bin"));
@@ -59,26 +63,26 @@ public class TestOle10Native {
                 POIDataSamples.getDocumentInstance().getFile("Bug53380_3.doc"),
                 POIDataSamples.getDocumentInstance().getFile("Bug47731.doc")
         };
-        
+
         for (File f : files) {
             POIFSFileSystem fs = new POIFSFileSystem(f, true);
             List<Entry> entries = new ArrayList<>();
             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();
         }
     }
@@ -97,14 +101,11 @@ public class TestOle10Native {
     }
 
     @Test
-    public void testOleNativeOOM() throws IOException {
+    public void testOleNativeOOM() throws IOException, Ole10NativeException {
         POIFSFileSystem fs = new POIFSFileSystem(dataSamples.openResourceAsStream("60256.bin"));
-        try {
-            Ole10Native.createFromEmbeddedOleObject(fs);
-            fail("Should have thrown exception because OLENative lacks a length parameter");
-        } catch (Ole10NativeException e) {
-            assertContains(e.getMessage(), "declared data length");
-        }
+        thrown.expect(RecordFormatException.class);
+        thrown.expectMessage("Tried to allocate");
+        Ole10Native.createFromEmbeddedOleObject(fs);
     }
 
 }

Added: poi/trunk/test-data/spreadsheet/bug64512_embed.xlsx
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/bug64512_embed.xlsx?rev=1878730&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/spreadsheet/bug64512_embed.xlsx
------------------------------------------------------------------------------
    svn:executable = *

Propchange: poi/trunk/test-data/spreadsheet/bug64512_embed.xlsx
------------------------------------------------------------------------------
--- svn:mime-type (added)
+++ svn:mime-type Thu Jun 11 00:43:45 2020
@@ -0,0 +1 @@
+application/vnd.openxmlformats-officedocument.spreadsheetml.sheet



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org