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 2017/12/31 01:14:09 UTC

svn commit: r1819710 [1/2] - in /poi: site/src/documentation/content/xdocs/ trunk/src/examples/src/org/apache/poi/hslf/examples/ trunk/src/java/org/apache/poi/sl/usermodel/ trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/ trunk/src/ooxml/testcases/o...

Author: kiwiwings
Date: Sun Dec 31 01:14:08 2017
New Revision: 1819710

URL: http://svn.apache.org/viewvc?rev=1819710&view=rev
Log:
#61797 - Embed Excel / Ole objects into powerpoint

Added:
    poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectData.java   (with props)
    poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java   (with props)
    poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectShape.java   (with props)
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java   (with props)
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java   (with props)
    poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java
      - copied, changed from r1819709, poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java
Removed:
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java
Modified:
    poi/site/src/documentation/content/xdocs/status.xml
    poi/trunk/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java

Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Sun Dec 31 01:14:08 2017
@@ -68,6 +68,7 @@
         <summary-item>Provide new ooxml-schemas-1.4.jar</summary-item>
       </summary>
       <actions>
+        <action dev="PD" type="add" fixes-bug="61797" breaks-compatibility="true" module="SL Common">Embed Excel / Ole objects into powerpoint</action>
         <action dev="PD" type="fix" fixes-bug="61943" module="SL Common">narrow generics definition because of tighter java9 checks</action>
         <action dev="PD" type="add" fixes-bug="61942" module="OPC">Refactor PackagePartName handling and add getUnusedPartIndex method</action>
         <action dev="PD" type="fix" fixes-bug="61941" module="POIFS">Move Ole marker generation to Ole10Native</action>

Modified: poi/trunk/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java (original)
+++ poi/trunk/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java Sun Dec 31 01:14:08 2017
@@ -21,8 +21,8 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 
-import org.apache.poi.hslf.model.OLEShape;
 import org.apache.poi.hslf.usermodel.HSLFObjectData;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
 import org.apache.poi.hslf.usermodel.HSLFPictureData;
 import org.apache.poi.hslf.usermodel.HSLFPictureShape;
 import org.apache.poi.hslf.usermodel.HSLFShape;
@@ -67,19 +67,19 @@ public final class DataExtraction {
         for (HSLFSlide slide : ppt.getSlides()) {
             //extract embedded OLE documents
             for (HSLFShape shape : slide.getShapes()) {
-                if (shape instanceof OLEShape) {
+                if (shape instanceof HSLFObjectShape) {
                     oleIdx++;
-                    OLEShape ole = (OLEShape) shape;
+                    HSLFObjectShape ole = (HSLFObjectShape) shape;
                     HSLFObjectData data = ole.getObjectData();
                     String name = ole.getInstanceName();
                     if ("Worksheet".equals(name)) {
 
                         //read xls
                         @SuppressWarnings({ "unused", "resource" })
-                        HSSFWorkbook wb = new HSSFWorkbook(data.getData());
+                        HSSFWorkbook wb = new HSSFWorkbook(data.getInputStream());
 
                     } else if ("Document".equals(name)) {
-                        HWPFDocument doc = new HWPFDocument(data.getData());
+                        HWPFDocument doc = new HWPFDocument(data.getInputStream());
                         //read the word document
                         Range r = doc.getRange();
                         for(int k = 0; k < r.numParagraphs(); k++) {
@@ -93,8 +93,8 @@ public final class DataExtraction {
                         out.close();
                         doc.close();
                      }  else {
-                        FileOutputStream out = new FileOutputStream(ole.getProgID() + "-"+(oleIdx+1)+".dat");
-                        InputStream dis = data.getData();
+                        FileOutputStream out = new FileOutputStream(ole.getProgId() + "-"+(oleIdx+1)+".dat");
+                        InputStream dis = data.getInputStream();
                         byte[] chunk = new byte[2048];
                         int count;
                         while ((count = dis.read(chunk)) >= 0) {

Added: poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectData.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectData.java?rev=1819710&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectData.java (added)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectData.java Sun Dec 31 01:14:08 2017
@@ -0,0 +1,102 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.sl.usermodel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Common interface for OLE shapes, i.e. shapes linked to embedded documents
+ * 
+ * @since POI 4.0.0
+ */
+public interface ObjectData {
+    
+    /**
+     * Gets an input stream which returns the binary of the embedded data.
+     *
+     * @return the input stream which will contain the binary of the embedded data.
+     */
+    InputStream getInputStream() throws IOException;
+
+    
+    /**
+     * @return the object data as stream (for writing)
+     */
+    OutputStream getOutputStream() throws IOException;
+    
+    /**
+     * Convenience method to get the embedded data as byte array.
+     *
+     * @return the embedded data.
+     */
+    default byte[] getBytes() throws IOException {
+        try (InputStream is = getInputStream()) {
+            return IOUtils.toByteArray(is);
+        }
+    }
+    
+    /**
+     * @return does this ObjectData have an associated POIFS Directory Entry?
+     * (Not all do, those that don't have a data portion)
+     */
+    default boolean hasDirectoryEntry() {
+        try (final InputStream is = FileMagic.prepareToCheckMagic(getInputStream())) {
+            FileMagic fm = FileMagic.valueOf(is);
+            return fm == FileMagic.OLE2;
+        } catch (IOException e) {
+            POILogger LOG = POILogFactory.getLogger(ObjectData.class);
+            LOG.log(POILogger.WARN, "Can't determine filemagic of ole stream", e);
+            return false;
+        }
+    }
+
+    /**
+     * Gets the object data. Only call for ones that have
+     * data though. See {@link #hasDirectoryEntry()}.
+     * The caller has to close the corresponding POIFSFileSystem
+     *
+     * @return the object data as an OLE2 directory.
+     * @throws IOException if there was an error reading the data.
+     */
+    @SuppressWarnings("resource")
+    default DirectoryEntry getDirectory() throws IOException {
+        try (final InputStream is = getInputStream()) {
+            return new POIFSFileSystem(is).getRoot();
+        }
+    }
+
+    /**
+     * @return the OLE2 Class Name of the object
+     */
+    String getOLE2ClassName();
+
+    /**
+     * @return a filename suggestion - inspecting/interpreting the Directory object probably gives a better result
+     */
+    String getFileName();
+
+}

Propchange: poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java?rev=1819710&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java (added)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java Sun Dec 31 01:14:08 2017
@@ -0,0 +1,96 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.sl.usermodel;
+
+import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.hpsf.ClassIDPredefined;
+import org.apache.poi.util.Beta;
+
+@Beta
+public interface ObjectMetaData {
+    enum Application {
+        EXCEL_V8("Worksheet", "Excel.Sheet.8", "Package", ClassIDPredefined.EXCEL_V8),
+        EXCEL_V12("Worksheet", "Excel.Sheet.12", "Package", ClassIDPredefined.EXCEL_V12),
+        WORD_V8("Document", "Word.Document.8", "Package", ClassIDPredefined.WORD_V8),
+        WORD_V12("Document", "Word.Document.12", "Package", ClassIDPredefined.WORD_V12),
+        PDF("PDF", "AcroExch.Document", "Contents", ClassIDPredefined.PDF),
+        CUSTOM(null, null, null, null);
+        
+        String objectName;
+        String progId;
+        String oleEntry;
+        ClassID classId;
+        
+        Application(String objectName, String progId, String oleEntry, ClassIDPredefined classId) {
+            this.objectName = objectName;
+            this.progId = progId;
+            this.classId = (classId == null) ? null : classId.getClassID();
+            this.oleEntry = oleEntry;
+        }
+
+        public static Application lookup(String progId) {
+            for (Application a : values()) {
+                if (a.progId != null && a.progId.equals(progId)) {
+                    return a;
+                }
+            }
+            return null;
+        }
+        
+        
+        public ObjectMetaData getMetaData() {
+            return new ObjectMetaData() {
+                public String getObjectName() {
+                    return objectName;
+                }
+
+                public String getProgId() {
+                    return progId;
+                }
+                
+                public String getOleEntry() {
+                    return oleEntry;
+                }
+
+                public ClassID getClassID() {
+                    return classId;
+                }
+            };
+        }
+    }
+    
+    /**
+     * @return the name of the OLE shape
+     */
+    String getObjectName();
+    
+    /**
+     * @return the program id assigned to the OLE container application
+     */
+    String getProgId();
+    
+    /**
+     * @return the storage classid of the OLE entry
+     */
+    ClassID getClassID();
+    
+    /**
+     * @return the name of the OLE entry inside the oleObject#.bin
+     */
+    String getOleEntry();
+}

Propchange: poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectShape.java?rev=1819710&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectShape.java (added)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectShape.java Sun Dec 31 01:14:08 2017
@@ -0,0 +1,152 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.sl.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectMetaData.Application;
+import org.apache.poi.util.IOUtils;
+
+/**
+ * An shape which references an embedded OLE object
+ *
+ * @since POI 4.0.0
+ */
+public interface ObjectShape<
+    S extends Shape<S,P>,
+    P extends TextParagraph<S,P,? extends TextRun>
+> extends Shape<S,P>, PlaceableShape<S,P>  {
+
+    /**
+     * Returns the picture data for this picture.
+     *
+     * @return the picture data for this picture.
+     */
+    PictureData getPictureData();
+
+    /**
+     * Returns the ProgID that stores the OLE Programmatic Identifier.
+     * A ProgID is a string that uniquely identifies a given object, for example,
+     * "Word.Document.8" or "Excel.Sheet.8".
+     *
+     * @return the ProgID
+     */
+    String getProgId();
+    
+    /**
+     * Returns the full name of the embedded object,
+     *  e.g. "Microsoft Word Document" or "Microsoft Office Excel Worksheet".
+     *
+     * @return the full name of the embedded object
+     */
+    String getFullName();
+    
+    /**
+     * Updates the ole data. If there wasn't an object registered before, a new
+     * ole embedding is registered in the parent slideshow.<p>
+     * 
+     * For HSLF this needs to be a {@link POIFSFileSystem} stream.
+     *
+     * @param application a preset application enum
+     * @param metaData or a custom metaData object, can be {@code null} if the application has been set
+     *
+     * @return an {@link OutputStream} which receives the new data, the data will be persisted on {@code close()}
+     *
+     * @throws IOException if the linked object data couldn't be found or a new object data couldn't be initialized
+     */
+    OutputStream updateObjectData(ObjectMetaData.Application application, ObjectMetaData metaData) throws IOException;
+
+    /**
+     * Reads the ole data as stream - the application specific stream is served
+     * The {@link #readObjectDataRaw() raw data} serves the outer/wrapped object, which is usually a
+     * {@link POIFSFileSystem} stream, whereas this method return the unwrapped entry 
+     *
+     * @return an {@link InputStream} which serves the object data
+     * 
+     * @throws IOException if the linked object data couldn't be found
+     */
+    default InputStream readObjectData() throws IOException {
+        final String progId = getProgId();
+        if (progId == null) {
+            throw new IllegalStateException(
+                "Ole object hasn't been initialized or provided in the source xml. " +
+                "use updateObjectData() first or check the corresponding slideXXX.xml");
+        }
+
+        final Application app = Application.lookup(progId);
+
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
+        try (final InputStream is = FileMagic.prepareToCheckMagic(readObjectDataRaw())) {
+            final FileMagic fm = FileMagic.valueOf(is);
+            if (fm == FileMagic.OLE2) {
+                try (final POIFSFileSystem poifs = new POIFSFileSystem(is)) {
+                    String[] names = {
+                        (app == null) ? null : app.getMetaData().getOleEntry(),
+                        // fallback to the usual suspects
+                        "Package",
+                        "Contents",
+                        "CONTENTS",
+                        "CONTENTSV30",
+                    };
+                    final DirectoryNode root = poifs.getRoot();
+                    String entryName = null;
+                    for (String n : names) {
+                        if (root.hasEntry(n)) {
+                            entryName = n;
+                            break;
+                        }
+                    }
+                    if (entryName == null) {
+                        poifs.writeFilesystem(bos);
+                    } else {
+                        try (final InputStream is2 = poifs.createDocumentInputStream(entryName)) {
+                            IOUtils.copy(is2, bos);
+                        }
+                    }
+                }
+            } else {
+                IOUtils.copy(is, bos);
+            }
+        }
+
+        return new ByteArrayInputStream(bos.toByteArray());
+    }
+    
+    /**
+     * Convenience method to return the raw data as {@code InputStream}
+     *
+     * @return the raw data stream
+     *
+     * @throws IOException if the data couldn't be retrieved
+     */
+    default InputStream readObjectDataRaw() throws IOException {
+        return getObjectData().getInputStream();
+    }
+
+    /**
+     * @return the data object
+     */
+    ObjectData getObjectData();
+}

Propchange: poi/trunk/src/java/org/apache/poi/sl/usermodel/ObjectShape.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java Sun Dec 31 01:14:08 2017
@@ -84,4 +84,11 @@ public interface ShapeContainer<
      * @param numCols the number of columns
      */
 	TableShape<S,P> createTable(int numRows, int numCols);
+	
+	/**
+	 * Create a new OLE object shape with the given pictureData as preview image
+	 *
+	 * @param pictureData the preview image
+	 */
+    ObjectShape<?,?> createOleShape(PictureData pictureData);
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java Sun Dec 31 01:14:08 2017
@@ -18,20 +18,30 @@ package org.apache.poi.xslf.usermodel;
 
 import java.awt.Color;
 import java.awt.geom.Rectangle2D;
-
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.POIXMLDocumentPart.RelationPart;
+import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.Beta;
 import org.apache.xmlbeans.XmlObject;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 
 
-/**
- * @author Yegor Kozlov
- */
 @Beta
 public class XSLFDrawing {
     private XSLFSheet _sheet;
@@ -110,4 +120,12 @@ public class XSLFDrawing {
         shape.setAnchor(new Rectangle2D.Double());
         return shape;
     }
+
+    public XSLFObjectShape createOleShape(String pictureRel) {
+        CTGraphicalObjectFrame obj = _spTree.addNewGraphicFrame();
+        obj.set(XSLFObjectShape.prototype(_shapeId++, pictureRel));
+        XSLFObjectShape shape = new XSLFObjectShape(obj, _sheet);
+        shape.setAnchor(new Rectangle2D.Double());
+        return shape;
+    }
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java Sun Dec 31 01:14:08 2017
@@ -37,6 +37,7 @@ import org.apache.poi.util.Units;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
@@ -86,13 +87,24 @@ public class XSLFGraphicFrame extends XS
 
 
     static XSLFGraphicFrame create(CTGraphicalObjectFrame shape, XSLFSheet sheet){
-        String uri = shape.getGraphic().getGraphicData().getUri();
-        if(XSLFTable.TABLE_URI.equals(uri)){
+        switch (getUri(shape)) {
+        case XSLFTable.TABLE_URI:
             return new XSLFTable(shape, sheet);
-        } else {
+        case XSLFObjectShape.OLE_URI:
+            return new XSLFObjectShape(shape, sheet);
+        default:
             return new XSLFGraphicFrame(shape, sheet);
         }
     }
+    
+    private static String getUri(CTGraphicalObjectFrame shape) {
+        final CTGraphicalObject g = shape.getGraphic();
+        if (g == null) {
+            return null;
+        }
+        CTGraphicalObjectData gd = g.getGraphicData();
+        return (gd == null) ? null : gd.getUri();
+    }
 
     /**
      * Rotate this shape.

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java Sun Dec 31 01:14:08 2017
@@ -19,6 +19,7 @@
 
 package org.apache.poi.xslf.usermodel;
 
+import java.awt.Dimension;
 import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -44,6 +45,7 @@ import org.openxmlformats.schemas.presen
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 
@@ -275,6 +277,29 @@ implements XSLFShapeContainer, GroupShap
         return sh;
     }
 
+    @Override
+    public XSLFObjectShape createOleShape(PictureData pictureData) {
+        if (!(pictureData instanceof XSLFPictureData)) {
+            throw new IllegalArgumentException("pictureData needs to be of type XSLFPictureData");
+        }
+        XSLFPictureData xPictureData = (XSLFPictureData)pictureData;
+        PackagePart pic = xPictureData.getPackagePart();
+
+        PackageRelationship rel = getSheet().getPackagePart().addRelationship(
+                pic.getPartName(), TargetMode.INTERNAL, XSLFRelation.IMAGES.getRelation());
+        
+        XSLFObjectShape sh = getDrawing().createOleShape(rel.getId());
+        CTOleObject oleObj = sh.getCTOleObject();
+        Dimension dim = pictureData.getImageDimension();
+        oleObj.setImgW(Units.toEMU(dim.getWidth()));
+        oleObj.setImgH(Units.toEMU(dim.getHeight()));
+        
+        
+        getShapes().add(sh);
+        sh.setParent(this);
+        return sh;
+    }
+    
     public XSLFTable createTable(){
         XSLFTable sh = getDrawing().createTable();
         _shapes.add(sh);

Added: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java?rev=1819710&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java Sun Dec 31 01:14:08 2017
@@ -0,0 +1,93 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.xslf.usermodel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.sl.usermodel.ObjectData;
+import org.apache.poi.util.Beta;
+
+/**
+ * An XSLFOleData instance holds the ole binary stream/object  
+ */
+@Beta
+public final class XSLFObjectData extends POIXMLDocumentPart implements ObjectData {
+
+    /**
+     * Create a new XSLFOleData node
+     */
+    protected XSLFObjectData() {
+        super();
+    }
+
+    /**
+     * Construct XSLFOleData from a package part
+     *
+     * @param part the package part holding the ole data
+     * 
+     * @since POI 3.14-Beta1
+     */
+    public XSLFObjectData(final PackagePart part) {
+        super(part);
+    }    
+
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return getPackagePart().getInputStream();
+    }
+
+    @Override
+    public OutputStream getOutputStream() throws IOException {
+        final PackagePart pp = getPackagePart();
+        pp.clear();
+        return pp.getOutputStream();
+    }
+    
+    /**
+     * *PictureData objects store the actual content in the part directly without keeping a
+     * copy like all others therefore we need to handle them differently.
+     */
+    @Override
+    protected void prepareForCommit() {
+        // do not clear the part here
+    }
+
+
+    public void setData(final byte[] data) throws IOException {
+        try (final OutputStream os = getPackagePart().getOutputStream()) {
+            os.write(data);
+        }
+    }
+
+    @Override
+    public String getOLE2ClassName() {
+        return null;
+    }
+
+    @Override
+    public String getFileName() {
+        return null;
+    }
+}
\ No newline at end of file

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java?rev=1819710&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java Sun Dec 31 01:14:08 2017
@@ -0,0 +1,323 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.xslf.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.xml.namespace.QName;
+
+import org.apache.poi.POIXMLDocumentPart.RelationPart;
+import org.apache.poi.POIXMLException;
+import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.Ole10Native;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectMetaData;
+import org.apache.poi.sl.usermodel.ObjectMetaData.Application;
+import org.apache.poi.sl.usermodel.ObjectShape;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.Internal;
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrameNonVisual;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual;
+
+public class XSLFObjectShape extends XSLFGraphicFrame implements ObjectShape<XSLFShape,XSLFTextParagraph> {
+
+    /* package */ static final String OLE_URI = "http://schemas.openxmlformats.org/presentationml/2006/ole";
+
+    private CTOleObject _oleObject;
+    private XSLFPictureData _data;
+
+    /*package*/ XSLFObjectShape(CTGraphicalObjectFrame shape, XSLFSheet sheet){
+        super(shape, sheet);
+
+        CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
+        XmlCursor xc = god.newCursor();
+        // select oleObj potentially under AlternateContent
+        // usually the mc:Choice element will be selected first
+        xc.selectPath("declare namespace p='"+PML_NS+"' .//p:oleObj");
+        try {
+            if (!xc.toNextSelection()) {
+                throw new IllegalStateException("p:oleObj element was not found in\n " + god);
+            }
+
+            XmlObject xo = xc.getObject();
+            // Pesky XmlBeans bug - see Bugzilla #49934
+            // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
+            if (xo instanceof XmlAnyTypeImpl){
+                String errStr =
+                    "Schemas (*.xsb) for CTOleObject can't be loaded - usually this happens when OSGI " +
+                    "loading is used and the thread context classloader has no reference to " +
+                    "the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
+                    "e.g. with CTOleObject.class.getClassLoader()"
+                ;
+                throw new IllegalStateException(errStr);
+            }
+            _oleObject = (CTOleObject)xo;
+        } finally {
+            xc.dispose();
+        }
+    }
+
+    @Internal
+    public CTOleObject getCTOleObject(){
+        return _oleObject;
+    }
+
+    @Override
+    public XSLFObjectData getObjectData() {
+        String oleRel = getCTOleObject().getId();
+        return getSheet().getRelationPartById(oleRel).getDocumentPart();
+    }
+
+    @Override
+    public String getProgId() {
+        return (_oleObject == null) ? null : _oleObject.getProgId();
+    }
+    
+    @Override
+    public String getFullName() {
+        return (_oleObject == null) ? null : _oleObject.getName();
+    }
+    
+    
+    /**
+     * Return the data on the (internal) picture.
+     * For an external linked picture, will return null
+     */
+    @Override
+    public XSLFPictureData getPictureData() {
+        if(_data == null){
+            String blipId = getBlipId();
+            if (blipId == null) {
+                return null;
+            }
+
+            PackagePart p = getSheet().getPackagePart();
+            PackageRelationship rel = p.getRelationship(blipId);
+            if (rel != null) {
+                try {
+                    PackagePart imgPart = p.getRelatedPart(rel);
+                    _data = new XSLFPictureData(imgPart);
+                }
+                catch (Exception e) {
+                    throw new POIXMLException(e);
+                }
+            }
+        }
+        return _data;
+    }
+
+    protected CTBlip getBlip(){
+        return getBlipFill().getBlip();
+    }
+
+    protected String getBlipId(){
+        String id = getBlip().getEmbed();
+        if (id.isEmpty()) {
+            return null;
+        }
+        return id;
+    }
+
+    protected CTBlipFillProperties getBlipFill() {
+        String xquery =
+                "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' "
+              + ".//p:blipFill"
+              ;
+        XmlObject xo = selectProperty(XmlObject.class, xquery);
+        try {
+            xo = CTPicture.Factory.parse(xo.getDomNode());
+        } catch (XmlException xe) {
+            return null;
+        }
+        return ((CTPicture)xo).getBlipFill();
+    }
+
+
+    @Override
+    public OutputStream updateObjectData(final Application application, final ObjectMetaData metaData) throws IOException {
+        final ObjectMetaData md = (application != null) ? application.getMetaData() : metaData;
+        if (md == null || md.getClassID() == null) {
+            throw new IllegalArgumentException("either application and/or metaData needs to be set.");
+        }
+
+
+        final XSLFSheet sheet = getSheet();
+
+        final RelationPart rp;
+        if (_oleObject.isSetId()) {
+            // object data was already set
+            rp = sheet.getRelationPartById(_oleObject.getId());
+        } else {
+            // object data needs to be initialized
+            try {
+                final XSLFRelation descriptor = XSLFRelation.OLE_OBJECT;
+                final OPCPackage pack = sheet.getPackagePart().getPackage();
+                int nextIdx = pack.getUnusedPartIndex(descriptor.getDefaultFileName());
+                rp = sheet.createRelationship(descriptor, XSLFFactory.getInstance(), nextIdx, false);
+                _oleObject.setId(rp.getRelationship().getId());
+            } catch (InvalidFormatException e) {
+                throw new IOException("Unable to add new ole embedding", e);
+            }
+
+            // setting spid only works with a vml drawing object
+            // oleObj.setSpid("_x0000_s"+(1025+objectIdx));
+        }
+
+        _oleObject.setProgId(md.getProgId());
+        _oleObject.setName(md.getObjectName());
+
+        return new XSLFObjectOutputStream(rp.getDocumentPart().getPackagePart(),md);
+    }
+
+    private static class XSLFObjectOutputStream extends ByteArrayOutputStream {
+        final PackagePart objectPart;
+        final ObjectMetaData metaData;
+        private XSLFObjectOutputStream(final PackagePart objectPart, final ObjectMetaData metaData) {
+            super(100000);
+            this.objectPart = objectPart;
+            this.metaData = metaData;
+        }
+
+        public void close() throws IOException {
+            objectPart.clear();
+            try (final OutputStream os = objectPart.getOutputStream()) {
+                final ByteArrayInputStream bis = new ByteArrayInputStream(this.buf, 0, size());
+                final FileMagic fm = FileMagic.valueOf(this.buf);
+
+                if (fm == FileMagic.OLE2) {
+                    try (final POIFSFileSystem poifs = new POIFSFileSystem(bis)) {
+                        poifs.getRoot().setStorageClsid(metaData.getClassID());
+                        poifs.writeFilesystem(os);
+                    }
+                } else if (metaData.getOleEntry() == null) {
+                    // OLE Name hasn't been specified, pass the input through
+                    os.write(this.buf, 0, size());
+                } else {
+                    try (final POIFSFileSystem poifs = new POIFSFileSystem()) {
+                        final ClassID clsId = metaData.getClassID();
+                        if (clsId != null) {
+                            poifs.getRoot().setStorageClsid(clsId);
+                        }
+                        poifs.createDocument(bis, metaData.getOleEntry());
+
+                        Ole10Native.createOleMarkerEntry(poifs);
+
+                        poifs.writeFilesystem(os);
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     *
+     *
+     * @param shapeId 1-based shapeId
+     * @param picRel relationship to the picture data in the ooxml package
+     * @return
+     */
+    static CTGraphicalObjectFrame prototype(int shapeId, String picRel){
+        CTGraphicalObjectFrame frame = CTGraphicalObjectFrame.Factory.newInstance();
+        CTGraphicalObjectFrameNonVisual nvGr = frame.addNewNvGraphicFramePr();
+
+        CTNonVisualDrawingProps cnv = nvGr.addNewCNvPr();
+        // usually the shape name has its index based on the n-th embeding, but having
+        // the prototype separate from the actual updating of the object, we use the shape id
+        cnv.setName("Object " + (shapeId + 1));
+        cnv.setId(shapeId + 1);
+
+        // add empty property elements otherwise Powerpoint doesn't load the file ...
+        nvGr.addNewCNvGraphicFramePr();
+        nvGr.addNewNvPr();
+
+        frame.addNewXfrm();
+        CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
+        gr.setUri(OLE_URI);
+        XmlCursor grCur = gr.newCursor();
+        grCur.toEndToken();
+        grCur.beginElement(new QName(PML_NS, "oleObj"));
+        grCur.insertElement(new QName(PML_NS, "embed"));
+
+
+        CTGroupShape grpShp = CTGroupShape.Factory.newInstance();
+        CTPicture pic = grpShp.addNewPic();
+        CTPictureNonVisual nvPicPr = pic.addNewNvPicPr();
+        CTNonVisualDrawingProps cNvPr = nvPicPr.addNewCNvPr();
+        cNvPr.setName("");
+        cNvPr.setId(0);
+        nvPicPr.addNewCNvPicPr();
+        nvPicPr.addNewNvPr();
+
+
+        CTBlipFillProperties blip = pic.addNewBlipFill();
+        blip.addNewBlip().setEmbed(picRel);
+        blip.addNewStretch().addNewFillRect();
+
+        CTShapeProperties spPr = pic.addNewSpPr();
+        CTTransform2D xfrm = spPr.addNewXfrm();
+        CTPoint2D off = xfrm.addNewOff();
+        off.setX(1270000);
+        off.setY(1270000);
+        CTPositiveSize2D xext = xfrm.addNewExt();
+        xext.setCx(1270000);
+        xext.setCy(1270000);
+
+        spPr.addNewPrstGeom().setPrst(STShapeType.RECT);
+
+
+        XmlCursor picCur = grpShp.newCursor();
+        picCur.toStartDoc();
+        picCur.moveXmlContents(grCur);
+        picCur.dispose();
+
+        grCur.dispose();
+
+
+        return frame;
+    }
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java Sun Dec 31 01:14:08 2017
@@ -231,6 +231,14 @@ public class XSLFRelation extends POIXML
           XSLFTableStyles.class
     );
 
+    public static final XSLFRelation OLE_OBJECT = new XSLFRelation(
+        "application/vnd.openxmlformats-officedocument.oleObject",
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject",
+        "/ppt/embeddings/oleObject#.bin", 
+        XSLFObjectData.class
+    );
+    
+    
    private XSLFRelation(String type, String rel, String defaultName, Class<? extends POIXMLDocumentPart> cls) {
       super(type, rel, defaultName, cls);
       _table.put(rel, this);

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java Sun Dec 31 01:14:08 2017
@@ -18,6 +18,7 @@ package org.apache.poi.xslf.usermodel;
 
 import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
 
+import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.io.IOException;
 import java.io.InputStream;
@@ -45,13 +46,23 @@ import org.apache.poi.sl.draw.Drawable;
 import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.sl.usermodel.Placeholder;
 import org.apache.poi.sl.usermodel.Sheet;
-import org.apache.poi.util.*;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Units;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlOptions;
 import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
-import org.openxmlformats.schemas.presentationml.x2006.main.*;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 
 @Beta
 public abstract class XSLFSheet extends POIXMLDocumentPart
@@ -256,6 +267,28 @@ implements XSLFShapeContainer, Sheet<XSL
     }
 
 
+    @Override
+    public XSLFObjectShape createOleShape(PictureData pictureData) {
+        if (!(pictureData instanceof XSLFPictureData)) {
+            throw new IllegalArgumentException("pictureData needs to be of type XSLFPictureData");
+        }
+        XSLFPictureData xPictureData = (XSLFPictureData)pictureData;
+        PackagePart pic = xPictureData.getPackagePart();
+
+        RelationPart rp = addRelation(null, XSLFRelation.IMAGES, new XSLFPictureData(pic));
+        
+        XSLFObjectShape sh = getDrawing().createOleShape(rp.getRelationship().getId());
+        CTOleObject oleObj = sh.getCTOleObject();
+        Dimension dim = pictureData.getImageDimension();
+        oleObj.setImgW(Units.toEMU(dim.getWidth()));
+        oleObj.setImgH(Units.toEMU(dim.getHeight()));
+        
+        
+        getShapes().add(sh);
+        sh.setParent(this);
+        return sh;
+    }
+
     /**
      * Returns an iterator over the shapes in this sheet
      *

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java Sun Dec 31 01:14:08 2017
@@ -59,25 +59,28 @@ public class XSLFTable extends XSLFGraph
 
         CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
         XmlCursor xc = god.newCursor();
-        if (!xc.toChild(DRAWINGML_URI, "tbl")) {
-            throw new IllegalStateException("a:tbl element was not found in\n " + god);
+        try {
+            if (!xc.toChild(DRAWINGML_URI, "tbl")) {
+                throw new IllegalStateException("a:tbl element was not found in\n " + god);
+            }
+    
+            XmlObject xo = xc.getObject();
+            // Pesky XmlBeans bug - see Bugzilla #49934
+            // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
+            if (xo instanceof XmlAnyTypeImpl){
+                String errStr =
+                    "Schemas (*.xsb) for CTTable can't be loaded - usually this happens when OSGI " +
+                    "loading is used and the thread context classloader has no reference to " +
+                    "the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
+                    "e.g. with CTTable.class.getClassLoader()"
+                ;
+                throw new IllegalStateException(errStr);
+            }
+            _table = (CTTable)xo;
+        } finally {
+            xc.dispose();
         }
 
-        XmlObject xo = xc.getObject();
-        // Pesky XmlBeans bug - see Bugzilla #49934
-        // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
-        if (xo instanceof XmlAnyTypeImpl){
-            String errStr =
-                "Schemas (*.xsb) for CTTable can't be loaded - usually this happens when OSGI " +
-                "loading is used and the thread context classloader has no reference to " +
-                "the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
-                "e.g. with CTTable.class.getClassLoader()"
-            ;
-            throw new IllegalStateException(errStr);
-        }
-        _table = (CTTable)xo;
-        xc.dispose();
-
         _rows = new ArrayList<>(_table.sizeOfTrArray());
         for(CTTableRow row : _table.getTrArray()) {
             _rows.add(new XSLFTableRow(row, this));

Added: poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java?rev=1819710&view=auto
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java (added)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java Sun Dec 31 01:14:08 2017
@@ -0,0 +1,220 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.sl;
+
+import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V12;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V8;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.PDF;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V12;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V8;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.poifs.storage.RawDataUtil;
+import org.apache.poi.sl.usermodel.ObjectMetaData;
+import org.apache.poi.sl.usermodel.ObjectShape;
+import org.apache.poi.sl.usermodel.PictureData;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TestOleShape {
+    private static final String PDF_SAMPLE =
+        "H4sIAAAAAAAAAJWUezRUWxzHe+o2FXncVtxLpxi3FPOeKYspjMdM5J1S4TTOaDIzxzpzJo9CUrnrSiUxIeT" +
+        "9jB7yqInihrhepTwqt1AT5VZCC7XcY0LWcv+5Z521zz6fvX+/vb/7t9cX78CyMiQZ0XD4W4OFEzgKQATgg4" +
+        "dxJiYAwRYS+aCHACqGnHAAABCs+AIUQrCvAEQhFsSFvSEck4kTowgECnEBl6E4OxGesfLkl2Bc0g5V/MCHt" +
+        "duqroTFC27YIKGAp+OL5Ou1SsmebA1XvciLk+Ucg84aLclQZhRZmh0amrG9Ina4t7Lh+ZCAHyezsg/NXsZg" +
+        "vuPw8NIedsrI2sZlz2vfhLkZfIgfMr4zFvTrmfbRgMmPw1UTvWk+r4MCZfLtj2WPPStVJ0P2PiKkxo+YnJ5" +
+        "Ua7v5UnefkB9ev0vSR37a8NrsC2lApaLp7086wS3Lzi2LqB3TMW2POrdRRUYMFYWs8vBo/kSQ6dYXpR6rxM" +
+        "UXM0vqu4arpe5dha7XS5MYS5P1arVG653sb8pXqReVw/TfjK8R3q4Z7X7Uk9dZ2Bcl8Wpmsl80Xf1QTOxe3" +
+        "Nutwus0kYge1LoHvgKLbc/f6WvdcsBfS9ctU3vSaneHNm0w/uhrm0Zett5O83s2xh2Gm8WZfWJ+/CNWruZ2" +
+        "cap8tR2/U9bAfRBbYt3PL9jvb3+0usqSF6vfrFuEq8Hf6jgrx/fERpZJEjKbHtJ11jCdUwI7Oc8QrmZf2pr" +
+        "L43WJn1mlT1ydV+QbrndcdN3qSEnicVhmoJyfWyprUEsIZlPyvi0tiEy7FzkOnqlE/qC6xFSpyg0E8tODa7" +
+        "qiKX61hMxRkZt73ITLWIHwtZtj71NbS4/BgKHnssOMcXOp1aacX4A//V+VFN4TWl6QryxdkcAp79BZcipmP" +
+        "OWOWkS6KhqUWlG+yCCxVMMtfW+9e56++gKHYEs9PNJztTI6KtyfOCDPOBppt3udRs3NpGrKfrs3i3Nivtrs" +
+        "VTl5LFerXZlTbf5XumbeYsOfwnve5ksEjKy6s1Z78rpbeJq7biTdzWwU3vhZ1GqkYb9D+t6mYvWLhXn6FWi" +
+        "c60VWpbBtVYHLQkmbh6Txwm6Ul3LbNW/Hs5FtLnlNX3fsAX2jPdlOI5W3HDIcm2MyNiR39rdyHlpwusjoOj" +
+        "I3IKfgPMILSzHZInmQaWyUFXEi0bHsCLX8pm9Gzl2vou7E3rrkPYdt1EwW3R5Qcg8rwzk88c1p13l8v+WkY" +
+        "75FHeS7XrvRsHgLy+wfr2EBRfNJ/4UVhUrihRqDktXciPGxWv1eXs396/0lqWG3YtU/A+D90hrT46cumSUN" +
+        "rBdG0G2Knn3T9Kw0X96vbhxMyr92uqUNOa4aEnGqP8us6GULm7mIyFKuxnOW2MZEEuKXmOpxnnqlwiMn+ju" +
+        "Xu+inC5mpG9oesxKkhcJq9bra5vR3H7l10hGbAxqu6t0LvHzaDnPIp/zeu0iXj1NNtVc+cMyUsH18u7TGXJ" +
+        "XiL4W3tqaL2mq6zkgXWB6kOTB3RxW8PHAOvzfaufDptdg7qmZlEcrUzbd5jKtVb85Sr9jaMT8a3y2Q30+3/" +
+        "FrsfGZDblh/mYnHhCg3ekm2q1JIYEVCd9rv42PNb9RFpuSsa4MNE0GfdSYDv6lsudikg4NE3tNugfWmfIY6" +
+        "7TeYvZCItG0zmDxrQwrjsQxArZ1RzHSA72CKgURgyqQszAASQOCCWItZETaAtdg7nYc2x85cAv0ggOAA+kC" +
+        "KnA4gAolQLGzG3ewgbz5oDgcA+zBEBEhUkhGDQiZvpc3tHlBMtYBFKBYsBiiz0dYILPGbs73vqynoDHLGKA" +
+        "KKxH5TK3MDZzAbQBEJNPNngc1iQUf4XMjJ2nxazxR3gsSwBOFCYoCsWPOHRtJ/ahQronbyvcWYnqljcJrdu" +
+        "2RK9pwE9DkJLLDioDACbOSCfAQGSEYkqhGJCGw8hKJ+xgSCgvogoN8hPldsBCM+mzZ9P0wE9pZwof8V92MD" +
+        "jHkKLEAUFMA+04XC1EzX6UdMAALxcERgK444+wB0Go1CA3jANCNRGdj1UoyIZhlpPsMobf48GmkeI1Pp8xi" +
+        "Nsm0eo9O3/mAoAvIFEKIQ58wPgrAtK+oJwyjAmL0+bBEPBugzGsUoiKAKhSQGmYjD4y3trXD/AmBc9IeqBwAA";
+    
+    enum Api { HSLF, XSLF };
+    
+    
+    @Parameter(value = 0)
+    public Api api;
+    @Parameter(value = 1)
+    public ObjectMetaData.Application app;
+
+    
+    private static File pictureFile;
+
+    @BeforeClass
+    public static void initPicture() {
+        pictureFile = POIDataSamples.getSlideShowInstance().getFile("wrench.emf");
+    }
+    
+    
+    @Parameters(name="{0} {1}")
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+            { Api.HSLF, EXCEL_V8 },
+            { Api.HSLF, WORD_V8 },
+            { Api.HSLF, PDF },
+            { Api.XSLF, EXCEL_V12 },
+            { Api.XSLF, WORD_V12 },
+            { Api.XSLF, PDF },
+        });
+    }
+    
+    @Test
+    public void embedData() throws IOException, InvalidFormatException {
+        final ByteArrayInputStream pptBytes;
+        try (SlideShow<?,?> ppt = createSlideShow()) {
+            final PictureData picData = ppt.addPicture(pictureFile,  PictureType.EMF);
+            final Slide<?,?> slide = ppt.createSlide();
+            final ObjectShape<?,?> oleShape = slide.createOleShape(picData);
+            oleShape.setAnchor(new Rectangle2D.Double(100,100,100,100));
+            try (OutputStream os = oleShape.updateObjectData(app, null)) {
+                fillOleData(os);
+            }
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
+            ppt.write(bos);
+            pptBytes = new ByteArrayInputStream(bos.toByteArray());
+        }
+        try (SlideShow<?,?> ppt = SlideShowFactory.create(pptBytes)) {
+            final ObjectShape<?,?> oleShape = (ObjectShape<?,?>)ppt.getSlides().get(0).getShapes().get(0);
+            try (InputStream bis = oleShape.readObjectData()) {
+                validateOleData(bis);
+            }
+        }
+    }
+    
+    private SlideShow<?,?> createSlideShow() {
+        if (api == Api.XSLF) {
+            return new XMLSlideShow();
+        } else {
+            assumeFalse(xslfOnly());
+            return new HSLFSlideShow();
+        }
+    }
+
+
+    private void fillOleData(final OutputStream out) throws IOException {
+        switch (app) {
+        case EXCEL_V8:
+        case EXCEL_V12:
+            try (Workbook wb = (app == EXCEL_V12) ? new XSSFWorkbook() : new HSSFWorkbook()) {
+                wb.createSheet().createRow(0).createCell(0).setCellValue("test me");
+                wb.write(out);
+            }
+            break;
+        case WORD_V8:
+            try (InputStream is = POIDataSamples.getDocumentInstance().openResourceAsStream("simple.doc")) {
+                IOUtils.copy(is, out);
+            }
+            break;
+        case WORD_V12:
+            try (XWPFDocument doc = new XWPFDocument()) {
+                doc.createParagraph().createRun().setText("Test me");
+                doc.write(out);
+            }
+            break;
+        case PDF:
+            out.write(RawDataUtil.decompress(PDF_SAMPLE));
+            break;
+        default:
+        case CUSTOM:
+            fail("not implemented");
+            break;
+        }
+    }
+    
+    private void validateOleData(final InputStream in) throws IOException, InvalidFormatException {
+        switch (app) {
+        case EXCEL_V8:
+        case EXCEL_V12:
+            try (Workbook wb = WorkbookFactory.create(in)) {
+                assertEquals("test me", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
+            }
+            break;
+        case WORD_V8:
+            try (HWPFDocument doc = new HWPFDocument(in)) {
+                assertEquals("This is a simple file created with Word 97-SR2.\r", doc.getDocumentText());
+            }
+            break;
+        case WORD_V12:
+            try (XWPFDocument doc = new XWPFDocument(in)) {
+                assertEquals("Test me", doc.getParagraphs().get(0).getText());
+            }
+            break;
+        case PDF:
+            final byte[] expected = RawDataUtil.decompress(PDF_SAMPLE);
+            final byte[] actual = IOUtils.toByteArray(in);
+            assertArrayEquals(expected, actual);
+            break;
+        default:
+        case CUSTOM:
+            fail("not implemented");
+            break;
+        }
+        
+    }
+}

Propchange: poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java Sun Dec 31 01:14:08 2017
@@ -29,7 +29,6 @@ import org.apache.poi.POIOLE2TextExtract
 import org.apache.poi.hslf.model.Comment;
 import org.apache.poi.hslf.model.HSLFMetroShape;
 import org.apache.poi.hslf.model.HeadersFooters;
-import org.apache.poi.hslf.model.OLEShape;
 import org.apache.poi.hslf.usermodel.HSLFMasterSheet;
 import org.apache.poi.hslf.usermodel.HSLFNotes;
 import org.apache.poi.hslf.usermodel.HSLFShape;
@@ -41,6 +40,7 @@ import org.apache.poi.hslf.usermodel.HSL
 import org.apache.poi.hslf.usermodel.HSLFTableCell;
 import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
 import org.apache.poi.hslf.usermodel.HSLFTextShape;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@@ -194,13 +194,13 @@ public final class PowerPointExtractor e
 		return getText(false, true);
 	}
 
-	public List<OLEShape> getOLEShapes() {
-		List<OLEShape> list = new ArrayList<>();
+	public List<HSLFObjectShape> getOLEShapes() {
+		List<HSLFObjectShape> list = new ArrayList<>();
 
 		for (HSLFSlide slide : _slides) {
 			for (HSLFShape shape : slide.getShapes()) {
-				if (shape instanceof OLEShape) {
-					list.add((OLEShape) shape);
+				if (shape instanceof HSLFObjectShape) {
+					list.add((HSLFObjectShape) shape);
 				}
 			}
 		}

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java Sun Dec 31 01:14:08 2017
@@ -17,8 +17,8 @@
 
 package org.apache.poi.hslf.record;
 
-import java.io.OutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.POILogger;
@@ -31,7 +31,7 @@ public class ExEmbed extends RecordConta
     /**
      * Record header data.
      */
-    private byte[] _header;
+    private final byte[] _header;
 
     // Links to our more interesting children
     private RecordAtom embedAtom;
@@ -47,7 +47,7 @@ public class ExEmbed extends RecordConta
      * @param start the start offset into the byte array.
      * @param len the length of the slice in the byte array.
      */
-    protected ExEmbed(byte[] source, int start, int len) {
+    protected ExEmbed(final byte[] source, final int start, final int len) {
         // Grab the header
         _header = new byte[8];
         System.arraycopy(source,start,_header,0,8);
@@ -62,7 +62,7 @@ public class ExEmbed extends RecordConta
      *
      * @param embedAtom the new embedAtom
      */
-    protected ExEmbed(RecordAtom embedAtom) {
+    protected ExEmbed(final RecordAtom embedAtom) {
         this();
         _children[0] = this.embedAtom = embedAtom;
     }
@@ -81,11 +81,11 @@ public class ExEmbed extends RecordConta
         LittleEndian.putShort(_header, 2, (short)getRecordType());
 
         // Setup our child records
-        CString cs1 = new CString();
+        final CString cs1 = new CString();
         cs1.setOptions(0x1 << 4);
-        CString cs2 = new CString();
+        final CString cs2 = new CString();
         cs2.setOptions(0x2 << 4);
-        CString cs3 = new CString();
+        final CString cs3 = new CString();
         cs3.setOptions(0x3 << 4);
         _children[0] = new ExEmbedAtom();
         _children[1] = new ExOleObjAtom();
@@ -117,8 +117,8 @@ public class ExEmbed extends RecordConta
 
         for (int i = 2; i < _children.length; i++) {
             if (_children[i] instanceof CString){
-                CString cs = (CString)_children[i];
-                int opts = cs.getOptions() >> 4;
+                final CString cs = (CString)_children[i];
+                final int opts = cs.getOptions() >> 4;
                 switch(opts){
                     case 0x1: menuName = cs; break;
                     case 0x2: progId = cs; break;
@@ -134,8 +134,7 @@ public class ExEmbed extends RecordConta
      *
      * @return the {@link ExEmbedAtom}.
      */
-    public ExEmbedAtom getExEmbedAtom()
-    {
+    public ExEmbedAtom getExEmbedAtom() {
         return (ExEmbedAtom)embedAtom;
     }
 
@@ -144,8 +143,7 @@ public class ExEmbed extends RecordConta
      *
      * @return the {@link ExOleObjAtom}.
      */
-    public ExOleObjAtom getExOleObjAtom()
-    {
+    public ExOleObjAtom getExOleObjAtom() {
         return oleObjAtom;
     }
 
@@ -154,14 +152,13 @@ public class ExEmbed extends RecordConta
      *
      * @return the name used for menus and the Links dialog box.
      */
-    public String getMenuName()
-    {
+    public String getMenuName() {
         return menuName == null ? null : menuName.getText();
     }
 
-    public void setMenuName(String s)
-    {
-        if(menuName != null) menuName.setText(s);
+    public void setMenuName(final String menuName) {
+        this.menuName = safeCString(this.menuName, 0x1);
+        this.menuName.setText(menuName);
     }
 
     /**
@@ -169,28 +166,29 @@ public class ExEmbed extends RecordConta
      * 
      * @return the OLE Programmatic Identifier.
      */
-    public String getProgId()
-    {
+    public String getProgId() {
         return progId == null ? null : progId.getText();
     }
 
-    public void setProgId(String s)
-    {
-        if(progId != null) progId.setText(s);
+    public void setProgId(final String progId) {
+        this.progId = safeCString(this.progId, 0x2);
+        this.progId.setText(progId);
     }
+
+    
+    
     /**
      * Gets the name that appears in the paste special dialog.
      *
      * @return the name that appears in the paste special dialog.
      */
-    public String getClipboardName()
-    {
+    public String getClipboardName() {
         return clipboardName == null ? null : clipboardName.getText();
     }
 
-    public void setClipboardName(String s)
-    {
-        if(clipboardName != null) clipboardName.setText(s);
+    public void setClipboardName(final String clipboardName) {
+        this.clipboardName = safeCString(this.clipboardName, 0x3);
+        this.clipboardName.setText(clipboardName);
     }
     
     /**
@@ -199,6 +197,7 @@ public class ExEmbed extends RecordConta
      *
      * @return the record type.
      */
+    @Override
     public long getRecordType() {
         return RecordTypes.ExEmbed.typeID;
     }
@@ -210,7 +209,31 @@ public class ExEmbed extends RecordConta
      * @param out the output stream.
      * @throws IOException if there was an error writing to the stream.
      */
-    public void writeOut(OutputStream out) throws IOException {
+    @Override
+    public void writeOut(final OutputStream out) throws IOException {
         writeOut(_header[0],_header[1],getRecordType(),_children,out);
     }
+    
+    private CString safeCString(CString oldStr, int optionsId) {
+        CString newStr = oldStr;
+        if (newStr == null) {
+            newStr = new CString();
+            newStr.setOptions(optionsId << 4);
+        }
+
+        boolean found = false;
+        for (final Record r : _children) {
+            // for simplicity just check for object identity
+            if (r == newStr) {
+                found = true;
+                break;
+            }
+        }
+
+        if (!found) {
+            appendChildRecord(newStr);
+        }
+        
+        return newStr;
+    }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java Sun Dec 31 01:14:08 2017
@@ -39,8 +39,6 @@ import org.apache.poi.util.Units;
 
 /**
  *  Represents a group of shapes.
- *
- * @author Yegor Kozlov
  */
 public class HSLFGroupShape extends HSLFShape
 implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
@@ -361,5 +359,16 @@ implements HSLFShapeContainer, GroupShap
         s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100));
         addShape(s);
         return s;
+    }
+
+    @Override
+    public HSLFObjectShape createOleShape(PictureData pictureData) {
+        if (!(pictureData instanceof HSLFPictureData)) {
+            throw new IllegalArgumentException("pictureData needs to be of type HSLFPictureData");
+        }
+        HSLFObjectShape s = new HSLFObjectShape((HSLFPictureData)pictureData, this);
+        s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100));
+        addShape(s);
+        return s;
     }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java Sun Dec 31 01:14:08 2017
@@ -16,17 +16,25 @@
 ==================================================================== */
 package org.apache.poi.hslf.usermodel;
 
-import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 import org.apache.poi.hslf.record.ExOleObjStg;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectData;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
 
 /**
  * A class that represents object data embedded in a slide show.
- *
- * @author Daniel Noll
  */
-public class HSLFObjectData {
+public class HSLFObjectData implements ObjectData {
+    private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectData.class);
+    
     /**
      * The record that contains the object data.
      */
@@ -41,14 +49,19 @@ public class HSLFObjectData {
         this.storage = storage;
     }
 
-    /**
-     * Gets an input stream which returns the binary of the embedded data.
-     *
-     * @return the input stream which will contain the binary of the embedded data.
-     */
-    public InputStream getData() {
+    @Override
+    public InputStream getInputStream() {
         return storage.getData();
     }
+    
+    @Override
+    public OutputStream getOutputStream() throws IOException {
+        return new ByteArrayOutputStream(100000) {
+            public void close() throws IOException {
+                setData(getBytes());
+            }
+        };
+    }
 
     /**
      * Sets the embedded data.
@@ -67,4 +80,15 @@ public class HSLFObjectData {
     public ExOleObjStg getExOleObjStg() {
         return storage;
     }
+
+
+    @Override
+    public String getOLE2ClassName() {
+        return null;
+    }
+
+    @Override
+    public String getFileName() {
+        return null;
+    }
 }

Copied: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java (from r1819709, poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java)
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java?p2=poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java&p1=poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java&r1=1819709&r2=1819710&rev=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java Sun Dec 31 01:14:08 2017
@@ -15,7 +15,12 @@
    limitations under the License.
 ==================================================================== */
 
-package org.apache.poi.hslf.model;
+package org.apache.poi.hslf.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 
 import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherProperties;
@@ -26,22 +31,22 @@ import org.apache.poi.hslf.record.ExObjR
 import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
 import org.apache.poi.hslf.record.Record;
 import org.apache.poi.hslf.record.RecordTypes;
-import org.apache.poi.hslf.usermodel.HSLFObjectData;
-import org.apache.poi.hslf.usermodel.HSLFPictureData;
-import org.apache.poi.hslf.usermodel.HSLFPictureShape;
-import org.apache.poi.hslf.usermodel.HSLFShape;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.Ole10Native;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectMetaData;
+import org.apache.poi.sl.usermodel.ObjectMetaData.Application;
+import org.apache.poi.sl.usermodel.ObjectShape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 
 
 /**
- * A shape representing embedded OLE obejct.
+ * A shape representing embedded OLE object.
  */
-public final class OLEShape extends HSLFPictureShape {
-    private static final POILogger LOG = POILogFactory.getLogger(OLEShape.class);
+public final class HSLFObjectShape extends HSLFPictureShape implements ObjectShape<HSLFShape,HSLFTextParagraph> {
+    private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectShape.class);
 
     private ExEmbed _exEmbed;
 
@@ -50,7 +55,7 @@ public final class OLEShape extends HSLF
      *
     * @param data the picture data
      */
-    public OLEShape(HSLFPictureData data){
+    public HSLFObjectShape(HSLFPictureData data){
         super(data);
     }
 
@@ -60,7 +65,7 @@ public final class OLEShape extends HSLF
      * @param data the picture data
      * @param parent the parent shape
      */
-    public OLEShape(HSLFPictureData data, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) {
+    public HSLFObjectShape(HSLFPictureData data, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) {
         super(data, parent);
     }
 
@@ -71,7 +76,7 @@ public final class OLEShape extends HSLF
       *        this picture in the <code>Slide</code>
       * @param parent the parent shape of this picture
       */
-    public OLEShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
+    public HSLFObjectShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
         super(escherRecord, parent);
     }
 
@@ -87,12 +92,12 @@ public final class OLEShape extends HSLF
     /**
      * Set the unique identifier for the OLE object and
      * register it in the necessary structures
-     * 
+     *
      * @param objectId the unique identifier for the OLE object
      */
     public void setObjectID(int objectId){
     	setEscherProperty(EscherProperties.BLIP__PICTUREID, objectId);
-    	
+
     	EscherContainerRecord ecr = getSpContainer();
     	EscherSpRecord spRecord = ecr.getChildById(EscherSpRecord.RECORD_ID);
         spRecord.setFlags(spRecord.getFlags()|EscherSpRecord.FLAG_OLESHAPE);
@@ -111,14 +116,13 @@ public final class OLEShape extends HSLF
         }
         uer.setExObjIdRef(objectId);
     }
-    
-    
+
+
     /**
      * Returns unique identifier for the OLE object.
      *
      * @return the unique identifier for the OLE object
      */
-    @SuppressWarnings("resource")
     public HSLFObjectData getObjectData(){
         HSLFSlideShow ppt = getSheet().getSlideShow();
         HSLFObjectData[] ole = ppt.getEmbeddedObjects();
@@ -129,9 +133,10 @@ public final class OLEShape extends HSLF
         if(exEmbed != null) {
             int ref = exEmbed.getExOleObjAtom().getObjStgDataRef();
 
-            for (int i = 0; i < ole.length; i++) {
-                if(ole[i].getExOleObjStg().getPersistId() == ref) {
-                    data=ole[i];
+            for (HSLFObjectData hod : ole) {
+                if(hod.getExOleObjStg().getPersistId() == ref) {
+                    data=hod;
+                    // keep searching to return the last persistent object with that refId
                 }
             }
         }
@@ -156,29 +161,40 @@ public final class OLEShape extends HSLF
      * 6. MetaFile( 4033), optional
      * </p>
      */
-    @SuppressWarnings("resource")
     public ExEmbed getExEmbed(){
-        if(_exEmbed == null){
+        return getExEmbed(false);
+    }
+
+    private ExEmbed getExEmbed(boolean create) {
+        if (_exEmbed == null) {
             HSLFSlideShow ppt = getSheet().getSlideShow();
 
-            ExObjList lst = ppt.getDocumentRecord().getExObjList(false);
+            ExObjList lst = ppt.getDocumentRecord().getExObjList(create);
             if(lst == null){
                 LOG.log(POILogger.WARN, "ExObjList not found");
                 return null;
             }
 
             int id = getObjectID();
-            Record[] ch = lst.getChildRecords();
-            for (int i = 0; i < ch.length; i++) {
-                if(ch[i] instanceof ExEmbed){
-                    ExEmbed embd = (ExEmbed)ch[i];
-                    if( embd.getExOleObjAtom().getObjID() == id) _exEmbed = embd;
+            for (Record ch : lst.getChildRecords()) {
+                if(ch instanceof ExEmbed){
+                    ExEmbed embd = (ExEmbed)ch;
+                    if( embd.getExOleObjAtom().getObjID() == id) {
+                        _exEmbed = embd;
+                    }
                 }
             }
+            
+            if (_exEmbed == null && create) {
+                _exEmbed = new ExEmbed();
+                _exEmbed.getExOleObjAtom().setObjID(id);
+                lst.appendChildRecord(_exEmbed);
+            }
         }
         return _exEmbed;
     }
-
+    
+    
     /**
      * Returns the instance name of the embedded object, e.g. "Document" or "Workbook".
      *
@@ -189,26 +205,63 @@ public final class OLEShape extends HSLF
         return (ee == null) ? null : ee.getMenuName();
     }
 
-    /**
-     * Returns the full name of the embedded object,
-     *  e.g. "Microsoft Word Document" or "Microsoft Office Excel Worksheet".
-     *
-     * @return the full name of the embedded object
-     */
+    @Override
     public String getFullName(){
         ExEmbed ee = getExEmbed();
         return (ee == null) ? null : ee.getClipboardName();
     }
 
-    /**
-     * Returns the ProgID that stores the OLE Programmatic Identifier.
-     * A ProgID is a string that uniquely identifies a given object, for example,
-     * "Word.Document.8" or "Excel.Sheet.8".
-     *
-     * @return the ProgID
-     */
-    public String getProgID(){
+    public void setFullName(final String fullName) {
+        getExEmbed(true).setClipboardName(fullName);
+    }
+
+    @Override
+    public String getProgId(){
         ExEmbed ee = getExEmbed();
         return (ee == null) ? null : ee.getProgId();
     }
+
+    public void setProgId(final String progId) {
+        getExEmbed(true).setProgId(progId);
+    }
+
+    public OutputStream updateObjectData(final Application application, final ObjectMetaData metaData) throws IOException {
+        final ObjectMetaData md = (application != null) ? application.getMetaData() : metaData;
+        if (md == null) {
+            throw new RuntimeException("either application or metaData needs to be set");
+        }
+
+        return new ByteArrayOutputStream(100000) {
+            public void close() throws IOException {
+                final FileMagic fm = FileMagic.valueOf(this.buf);
+                final ByteArrayInputStream bis = new ByteArrayInputStream(this.buf, 0, this.count);
+                final HSLFSlideShow ppt = getSheet().getSlideShow();
+
+                try (POIFSFileSystem poifs = (fm == FileMagic.OLE2) ? new POIFSFileSystem(bis) : new POIFSFileSystem()) {
+                    if (fm != FileMagic.OLE2) {
+                        poifs.createDocument(bis, md.getOleEntry());
+                    }
+
+                    Ole10Native.createOleMarkerEntry(poifs);
+
+                    poifs.getRoot().setStorageClsid(md.getClassID());
+
+
+                    int oid = getObjectID();
+                    if (oid == 0) {
+                        // assign new embedding
+                        oid = ppt.addEmbed(poifs);
+                        setObjectID(oid);
+                    } else {
+                        ByteArrayOutputStream bos = new ByteArrayOutputStream(this.size()+1000);
+                        poifs.writeFilesystem(bos);
+                        getObjectData().setData(bos.toByteArray());
+                    }
+
+                    setProgId(md.getProgId());
+                    setFullName(md.getObjectName());
+                }
+            }
+        };
+    }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java Sun Dec 31 01:14:08 2017
@@ -45,5 +45,6 @@ public interface HSLFShapeContainer exte
     @Override
     HSLFPictureShape createPicture(PictureData pictureData);
 
-
+    @Override
+    HSLFObjectShape createOleShape(PictureData pictureData);
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java Sun Dec 31 01:14:08 2017
@@ -31,7 +31,6 @@ import org.apache.poi.ddf.EscherSimplePr
 import org.apache.poi.ddf.EscherSpRecord;
 import org.apache.poi.ddf.EscherTextboxRecord;
 import org.apache.poi.hslf.model.MovieShape;
-import org.apache.poi.hslf.model.OLEShape;
 import org.apache.poi.hslf.record.ExObjRefAtom;
 import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
 import org.apache.poi.hslf.record.InteractiveInfo;
@@ -134,7 +133,7 @@ public final class HSLFShapeFactory {
         if(info != null && info.getInteractiveInfoAtom() != null){
             switch(info.getInteractiveInfoAtom().getAction()){
                 case InteractiveInfoAtom.ACTION_OLE:
-                    return new OLEShape(spContainer, parent);
+                    return new HSLFObjectShape(spContainer, parent);
                 case InteractiveInfoAtom.ACTION_MEDIA:
                     return new MovieShape(spContainer, parent);
                 default:
@@ -144,7 +143,7 @@ public final class HSLFShapeFactory {
         
         ExObjRefAtom oes = getClientDataRecord(spContainer, RecordTypes.ExObjRefAtom.typeID);
         return (oes != null)
-            ? new OLEShape(spContainer, parent)
+            ? new HSLFObjectShape(spContainer, parent)
             : new HSLFPictureShape(spContainer, parent);
     }
     

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java?rev=1819710&r1=1819709&r2=1819710&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java Sun Dec 31 01:14:08 2017
@@ -442,4 +442,15 @@ public abstract class HSLFSheet implemen
         addShape(s);
         return s;
     }
+
+    @Override
+    public HSLFObjectShape createOleShape(PictureData pictureData) {
+        if (!(pictureData instanceof HSLFPictureData)) {
+            throw new IllegalArgumentException("pictureData needs to be of type HSLFPictureData");
+        }
+        HSLFObjectShape s = new HSLFObjectShape((HSLFPictureData)pictureData);
+        s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100));
+        addShape(s);
+        return s;
+    }
 }



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