]> source.dussan.org Git - poi.git/commitdiff
Support for getting OLE object data from slide show
authorYegor Kozlov <yegor@apache.org>
Wed, 16 Apr 2008 11:57:15 +0000 (11:57 +0000)
committerYegor Kozlov <yegor@apache.org>
Wed, 16 Apr 2008 11:57:15 +0000 (11:57 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@648674 13f79535-47bb-0310-9956-ffa450edef68

12 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/hslf/how-to-shapes.xml
src/documentation/content/xdocs/status.xml
src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java
src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java [new file with mode: 0755]
src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java
src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java
src/scratchpad/src/org/apache/poi/hslf/record/PersistRecord.java [new file with mode: 0755]
src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java

index 817bd818b7cabc78d929890f11d6d28c3f56e60f..0b3a7005be8b0eee1b014057e7c7c19f89e9ca88 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.0.3-beta1" date="2008-04-??">
+           <action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
            <action dev="POI-DEVELOPERS" type="add">HSLF: Implemented more methods in PPGraphics2D</action>
            <action dev="POI-DEVELOPERS" type="add">HSLF: Added Freeform shape which can contain both lines and Bezier curves</action>
            <action dev="POI-DEVELOPERS" type="fix">41071 - Improved text extraction in HSLF</action>
index a94ab41fafa735d7368f24f4d5976228ed2cf6db..eec5ffcafabbb102ed5f6a6c5082ac8db435eb8c 100644 (file)
@@ -41,6 +41,9 @@
                     <li><link href="#Hyperlinks">Hyperlinks</link></li>
                     <li><link href="#Tables">Tables</link></li>
                     <li><link href="#RemoveShape">How to remove shapes</link></li>
+                    <li><link href="#OLE">How to retrieve embedded OLE objects</link></li>
+                    <li><link href="#Freeform">How to create shapes of arbitrary geometry</link></li>
+                    <li><link href="#Graphics2D">Shapes and Graphics2D</link></li>
                 </ul>
             </section>
             <section><title>Features</title>
                 </section>
                 <anchor id="GetShapes"/>
                 <section><title>How to get shapes contained in a particular slide</title>
-                  <p>The superclass of all shapes in HSLF is the Shape class - the elemental object that composes a drawing.
-                    The following pictute shows the class tree of HSLF shapes:
-                  </p>
-                  <p>
-                         <img src="images/hslf_shapes.gif" alt="Class Tree of HSLF Shapes" width="611" height="412"/>
-                  </p>
                   <p>
-                    The following fragment demonstrates how to iterate over shapes for each slide.
+                    The following code demonstrates how to iterate over shapes for each slide.
                   </p>
                     <source>
   SlideShow ppt = new SlideShow(new HSLFSlideShow("slideshow.ppt"));
         }
                     </source>
                   </section>
+                <anchor id="OLE"/>
+                <section><title>How to retrieve embedded OLE objects</title>
+                  <source>
 
-            </section>
+        Shape[] shape = slide.getShapes();
+        for (int i = 0; i &lt; shape.length; i++) {
+            if (shape[i] instanceof OLEShape) {
+                OLEShape ole = (OLEShape) shape[i];
+                ObjectData data = ole.getObjectData();
+                String name = ole.getInstanceName();
+                if ("Worksheet".equals(name)) {
+                    HSSFWorkbook wb = new HSSFWorkbook(data.getData());
+                } else if ("Document".equals(name)) {
+                    HWPFDocument doc = new HWPFDocument(data.getData());
+                }
+            }
+        }
+                    </source>
+                  </section>
+
+                <anchor id="Freeform"/>
+                <section><title>How to create shapes of arbitrary geometry</title>
+                  <source>
+
+        SlideShow ppt = new SlideShow();
+        Slide slide = ppt.createSlide();
+
+        java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
+        path.moveTo(100, 100);
+        path.lineTo(200, 100);
+        path.curveTo(50, 45, 134, 22, 78, 133);
+        path.curveTo(10, 45, 134, 56, 78, 100);
+        path.lineTo(100, 200);
+        path.closePath();
+        
+        Freeform shape = new Freeform();
+        shape.setPath(path);
+        slide.addShape(shape);
+                    </source>
+                  </section>
+
+                <anchor id="Graphics2D"/>
+                <section><title>How to draw into a slide using Graphics2D</title>
+                  <warning>
+                   Current implementation of the PowerPoint Graphics2D driver is not fully compliant with the java.awt.Graphics2D specification.
+                   Some features like clipping, drawing of images are not yet supported. 
+                  </warning>
+                  <source>
+        SlideShow ppt = new SlideShow();
+        Slide slide = ppt.createSlide();
+
+        //draw a simple bar graph
+        //bar chart data. The first value is the bar color, the second is the width
+        Object[] def = new Object[]{
+            Color.yellow, new Integer(100),
+            Color.green, new Integer(150),
+            Color.gray, new Integer(75),
+            Color.red, new Integer(200),
+        };
+
+        //all objects are drawn into a shape group so we need to create one
+
+        ShapeGroup group = new ShapeGroup();
+        //define position of the drawing in the slide
+        Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
+        //if you want to draw in the entire slide area then define the anchor as follows:
+        //Dimension pgsize = ppt.getPageSize();
+        //java.awt.Rectangle bounds = new java.awt.Rectangle(0, 0, pgsize.width, pgsize.height);
+
+        group.setAnchor(bounds);
+        slide.addShape(group);
+
+        //draw a simple bar chart
+        Graphics2D graphics = new PPGraphics2D(group);
+        int x = bounds.x + 50, y = bounds.y + 50;
+        graphics.setFont(new Font("Arial", Font.BOLD, 10));
+        for (int i = 0, idx = 1; i &lt; def.length; i+=2, idx++) {
+            graphics.setColor(Color.black);
+            int width = ((Integer)def[i+1]).intValue();
+            graphics.drawString("Q" + idx, x-20, y+20);
+            graphics.drawString(width + "%", x + width + 10, y + 20);
+            graphics.setColor((Color)def[i]);
+            graphics.fill(new Rectangle(x, y, width, 30));
+            y += 40;
+        }
+        graphics.setColor(Color.black);
+        graphics.setFont(new Font("Arial", Font.BOLD, 14));
+        graphics.draw(bounds);
+        graphics.drawString("Performance", x + 70, y + 40);
+
+        FileOutputStream out = new FileOutputStream("hslf-graphics2d.ppt");
+        ppt.write(out);
+        out.close();
+
+                   </source>
+                  </section>
+    
+                </section>
         </section>
     </body>
 </document>
index 6fb6c35c03705cb194caf0d3d9b554094039504b..9e3405591dec8139938ecef063148c5f125a8c6c 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.0.3-beta1" date="2008-04-??">
+           <action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
            <action dev="POI-DEVELOPERS" type="add">HSLF: Implemented more methods in PPGraphics2D</action>
            <action dev="POI-DEVELOPERS" type="add">HSLF: Added Freeform shape which can contain both lines and Bezier curves</action>
            <action dev="POI-DEVELOPERS" type="fix">41071 - Improved text extraction in HSLF</action>
index 29f01b31549c6abef090f8131288af1f96984f76..dc967fd5b4a3c46f6583247720f85421e1e206ef 100644 (file)
@@ -27,22 +27,13 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
 
 import org.apache.poi.POIDocument;
 import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
 import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
 import org.apache.poi.hslf.exceptions.HSLFException;
-import org.apache.poi.hslf.record.CurrentUserAtom;
-import org.apache.poi.hslf.record.ExOleObjStg;
-import org.apache.poi.hslf.record.PersistPtrHolder;
-import org.apache.poi.hslf.record.PositionDependentRecord;
-import org.apache.poi.hslf.record.Record;
-import org.apache.poi.hslf.record.UserEditAtom;
+import org.apache.poi.hslf.record.*;
 import org.apache.poi.hslf.usermodel.ObjectData;
 import org.apache.poi.hslf.usermodel.PictureData;
 import org.apache.poi.hslf.model.Shape;
@@ -253,6 +244,7 @@ public class HSLFSlideShow extends POIDocument
 
     private Record[] read(byte[] docstream, int usrOffset){
         ArrayList lst = new ArrayList();
+        HashMap offset2id = new HashMap(); 
         while (usrOffset != 0){
             UserEditAtom usr = (UserEditAtom) Record.buildRecordAtOffset(docstream, usrOffset);
             lst.add(new Integer(usrOffset));
@@ -266,6 +258,7 @@ public class HSLFSlideShow extends POIDocument
                 Integer offset = (Integer)entries.get(id);
 
                 lst.add(offset);
+                offset2id.put(offset, id);
             }
 
             usrOffset = usr.getLastUserEditAtomOffset();
@@ -278,6 +271,11 @@ public class HSLFSlideShow extends POIDocument
         for (int i = 0; i < a.length; i++) {
             Integer offset = (Integer)a[i];
             rec[i] = (Record)Record.buildRecordAtOffset(docstream, offset.intValue());
+            if(rec[i] instanceof PersistRecord) {
+                PersistRecord psr = (PersistRecord)rec[i];
+                Integer id = (Integer)offset2id.get(offset);
+                psr.setPersistId(id.intValue());
+            }
         }
 
         return rec;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java
new file mode 100755 (executable)
index 0000000..908dc4d
--- /dev/null
@@ -0,0 +1,171 @@
+/*\r
+* Licensed to the Apache Software Foundation (ASF) under one or more\r
+* contributor license agreements.  See the NOTICE file distributed with\r
+* this work for additional information regarding copyright ownership.\r
+* The ASF licenses this file to You under the Apache License, Version 2.0\r
+* (the "License"); you may not use this file except in compliance with\r
+* the License.  You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.hslf.usermodel.PictureData;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.usermodel.ObjectData;\r
+import org.apache.poi.hslf.record.Document;\r
+import org.apache.poi.hslf.record.ExObjList;\r
+import org.apache.poi.hslf.record.Record;\r
+import org.apache.poi.hslf.record.ExEmbed;\r
+import org.apache.poi.hslf.blip.Bitmap;\r
+import org.apache.poi.util.POILogger;\r
+\r
+import javax.imageio.ImageIO;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.*;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+import java.util.List;\r
+import java.util.Arrays;\r
+\r
+\r
+/**\r
+ * A shape representing embedded OLE obejct.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class OLEShape extends Picture {\r
+    protected ExEmbed _exEmbed;\r
+\r
+    /**\r
+     * Create a new <code>OLEShape</code>\r
+     *\r
+    * @param idx the index of the picture\r
+     */\r
+    public OLEShape(int idx){\r
+        super(idx);\r
+    }\r
+\r
+    /**\r
+     * Create a new <code>OLEShape</code>\r
+     *\r
+     * @param idx the index of the picture\r
+     * @param parent the parent shape\r
+     */\r
+    public OLEShape(int idx, Shape parent) {\r
+        super(idx, parent);\r
+    }\r
+\r
+    /**\r
+      * Create a <code>OLEShape</code> object\r
+      *\r
+      * @param escherRecord the <code>EscherSpContainer</code> record which holds information about\r
+      *        this picture in the <code>Slide</code>\r
+      * @param parent the parent shape of this picture\r
+      */\r
+     protected OLEShape(EscherContainerRecord escherRecord, Shape parent){\r
+        super(escherRecord, parent);\r
+    }\r
+\r
+    /**\r
+     * Returns unique identifier for the OLE object.\r
+     *\r
+     * @return the unique identifier for the OLE object\r
+     */\r
+    public int getObjectID(){\r
+        return getEscherProperty(EscherProperties.BLIP__PICTUREID);\r
+    }\r
+\r
+    /**\r
+     * Returns unique identifier for the OLE object.\r
+     *\r
+     * @return the unique identifier for the OLE object\r
+     */\r
+    public ObjectData getObjectData(){\r
+        SlideShow ppt = getSheet().getSlideShow();\r
+        ObjectData[] ole = ppt.getEmbeddedObjects();\r
+\r
+        //persist reference\r
+        int ref = getExEmbed().getExOleObjAtom().getObjStgDataRef();\r
+        for (int i = 0; i < ole.length; i++) {\r
+            if(ole[i].getExOleObjStg().getPersistId() == ref) return ole[i];\r
+\r
+        }\r
+        logger.log(POILogger.WARN, "OLE data not found");\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * Return the record container for this embedded object.\r
+     *\r
+     * <p>\r
+     * It contains:\r
+     * 1. ExEmbedAtom.(4045)\r
+     * 2. ExOleObjAtom (4035)\r
+     * 3. CString (4026), Instance MenuName (1) used for menus and the Links dialog box.\r
+     * 4. CString (4026), Instance ProgID (2) that stores the OLE Programmatic Identifier.\r
+     *     A ProgID is a string that uniquely identifies a given object.\r
+     * 5. CString (4026), Instance ClipboardName (3) that appears in the paste special dialog.\r
+     * 6. MetaFile( 4033), optional\r
+     * </p>\r
+     * @return\r
+     */\r
+    public ExEmbed getExEmbed(){\r
+        if(_exEmbed == null){\r
+            SlideShow ppt = getSheet().getSlideShow();\r
+\r
+            ExObjList lst = ppt.getDocumentRecord().getExObjList();\r
+            if(lst == null){\r
+                logger.log(POILogger.WARN, "ExObjList not found");\r
+                return null;\r
+            }\r
+\r
+            int id = getObjectID();\r
+            Record[] ch = lst.getChildRecords();\r
+            for (int i = 0; i < ch.length; i++) {\r
+                if(ch[i] instanceof ExEmbed){\r
+                    ExEmbed embd = (ExEmbed)ch[i];\r
+                    if( embd.getExOleObjAtom().getObjID() == id) _exEmbed = embd;\r
+                }\r
+            }\r
+        }\r
+        return _exEmbed;\r
+    }\r
+\r
+    /**\r
+     * Returns the instance name of the embedded object, e.g. "Document" or "Workbook".\r
+     *\r
+     * @return the instance name of the embedded object\r
+     */\r
+    public String getInstanceName(){\r
+        return getExEmbed().getMenuName();\r
+    }\r
+\r
+    /**\r
+     * Returns the full name of the embedded object,\r
+     *  e.g. "Microsoft Word Document" or "Microsoft Office Excel Worksheet".\r
+     *\r
+     * @return the full name of the embedded object\r
+     */\r
+    public String getFullName(){\r
+        return getExEmbed().getClipboardName();\r
+    }\r
+\r
+    /**\r
+     * Returns the ProgID that stores the OLE Programmatic Identifier.\r
+     * A ProgID is a string that uniquely identifies a given object, for example,\r
+     * "Word.Document.8" or "Excel.Sheet.8".\r
+     *\r
+     * @return the ProgID\r
+     */\r
+    public String getProgID(){\r
+        return getExEmbed().getProgId();\r
+    }\r
+}\r
index f93392a9a9bb601bc51eece34294e63b21c5e62e..7b67c35fb27e0efe9de99f3767352497808ee023 100644 (file)
@@ -294,7 +294,7 @@ public abstract class Shape {
    public int getEscherProperty(short propId){
         EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
         EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
-        return prop == null ? 0 : prop.getPropertyNumber();
+        return prop == null ? 0 : prop.getPropertyValue();
     }
 
     /**
index 76b43ebb8acae89773df3990942e1faab194ce89..4abc8c1c0040358285b47c1f743aed0fe20419ad 100644 (file)
@@ -76,13 +76,19 @@ public class ShapeFactory {
             case ShapeTypes.TextBox:
                 shape = new TextBox(spContainer, parent);
                 break;
-            case ShapeTypes.PictureFrame:
-                shape = new Picture(spContainer, parent);
+            case ShapeTypes.PictureFrame: {
+                EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
+                EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID);
+                if(prop != null)
+                    shape = new OLEShape(spContainer, parent); //presence of BLIP__PICTUREID indicates it is an embedded object 
+                else
+                    shape = new Picture(spContainer, parent);
                 break;
+            }
             case ShapeTypes.Line:
                 shape = new Line(spContainer, parent);
                 break;
-            case ShapeTypes.NotPrimitive:
+            case ShapeTypes.NotPrimitive: {
                 EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
                 EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
                 if(prop != null)
@@ -93,6 +99,7 @@ public class ShapeFactory {
                     shape = new AutoShape(spContainer, parent);
                 }
                 break;
+            }
             default:
                 shape = new AutoShape(spContainer, parent);
                 break;
index 7c47427927094576b2f033392fcd7b5078c3d753..197497fd027fe4e8d79fd6b0f514d145753416b7 100644 (file)
@@ -30,7 +30,10 @@ import org.apache.poi.util.LittleEndian;
  *
  * @author Daniel Noll
  */
-public class ExOleObjStg extends RecordAtom {
+public class ExOleObjStg extends RecordAtom implements PersistRecord {
+
+    private int _persistId; // Found from PersistPtrHolder
+
     /**
      * Record header.
      */
@@ -109,4 +112,19 @@ public class ExOleObjStg extends RecordAtom {
         out.write(_header);
         out.write(_data);
     }
+
+    /**
+     * Fetch our sheet ID, as found from a PersistPtrHolder.
+     * Should match the RefId of our matching SlidePersistAtom
+     */
+    public int getPersistId() {
+        return _persistId;
+    }
+
+    /**
+     * Set our sheet ID, as found from a PersistPtrHolder
+     */
+    public void setPersistId(int id) {
+        _persistId = id;
+    }
 }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/PersistRecord.java b/src/scratchpad/src/org/apache/poi/hslf/record/PersistRecord.java
new file mode 100755 (executable)
index 0000000..8238d10
--- /dev/null
@@ -0,0 +1,37 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+/**\r
+ * A record that can be referenced in PersistPtr storage.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public interface PersistRecord {\r
+\r
+    /**\r
+     * Fetch the persist ID\r
+     */\r
+    public int getPersistId();\r
+\r
+    /**\r
+     * Set the persist ID\r
+     */\r
+    public void setPersistId(int id);\r
+}\r
index 66b4f0373a8948dfb49fd58bf679fac34c1d6b08..957e78868ed6345a1fcc8769a69d865dc3bfac56 100644 (file)
@@ -48,4 +48,13 @@ public class ObjectData {
     public InputStream getData() {
         return storage.getData();
     }
+
+    /**
+     * Return the record that contains the object data.
+     *
+     * @return the record that contains the object data.
+     */
+    public ExOleObjStg getExOleObjStg() {
+        return storage;
+    }
 }
index 21e30ac2a9328f655408e72c094082ad60602c55..418dc3d2f031139e018daa973c12503ef3b3b3f8 100644 (file)
@@ -487,7 +487,13 @@ public class SlideShow
        public PictureData[] getPictureData() {
                return _hslfSlideShow.getPictures();
        }
-       
+
+    /**
+     * Returns the data of all the embedded OLE object in the SlideShow
+     */
+    public ObjectData[] getEmbeddedObjects() {
+        return _hslfSlideShow.getEmbeddedObjects();
+    }
        /**
         * Return the current page size
         */
index 7be6f9dc3253a9fcd05d98048556d92237415130..cb177048ba16e3950ad7ab4efa207bfb6e1c67da 100644 (file)
 package org.apache.poi.hslf.model;\r
 \r
 import java.io.*;\r
+import java.util.List;\r
+import java.util.ArrayList;\r
 \r
 import org.apache.poi.hslf.HSLFSlideShow;\r
 import org.apache.poi.hslf.usermodel.ObjectData;\r
 import org.apache.poi.hslf.usermodel.PictureData;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.hssf.usermodel.HSSFSheet;\r
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;\r
+import org.apache.poi.hwpf.HWPFDocument;\r
+import org.apache.poi.hwpf.usermodel.Range;\r
+import org.apache.poi.hwpf.usermodel.Paragraph;\r
 \r
 import junit.framework.TestCase;\r
 \r
@@ -59,4 +68,41 @@ public class TestOleEmbedding extends TestCase
             slideShow.close();\r
         }\r
     }\r
+\r
+    public void testOLEShape() throws Exception {\r
+        String dirname = System.getProperty("HSLF.testdata.path");\r
+        File file = new File(dirname, "ole2-embedding-2003.ppt");\r
+        FileInputStream is = new FileInputStream(file);\r
+        SlideShow ppt = new SlideShow(is);\r
+        is.close();\r
+\r
+        Slide slide = ppt.getSlides()[0];\r
+        Shape[] sh = slide.getShapes();\r
+        int cnt = 0;\r
+        for (int i = 0; i < sh.length; i++) {\r
+            if(sh[i] instanceof OLEShape){\r
+                cnt++;\r
+                OLEShape ole = (OLEShape)sh[i];\r
+                ObjectData data = ole.getObjectData();\r
+                if("Worksheet".equals(ole.getInstanceName())){\r
+                    //Voila! we created a workbook from the embedded OLE data\r
+                    HSSFWorkbook wb = new HSSFWorkbook(data.getData());\r
+                    HSSFSheet sheet = wb.getSheetAt(0);\r
+                    //verify we can access the xls data\r
+                    assertEquals(1, sheet.getRow(0).getCell((short)0).getNumericCellValue(), 0);\r
+                    assertEquals(1, sheet.getRow(1).getCell((short)0).getNumericCellValue(), 0);\r
+                    assertEquals(2, sheet.getRow(2).getCell((short)0).getNumericCellValue(), 0);\r
+                    assertEquals(3, sheet.getRow(3).getCell((short)0).getNumericCellValue(), 0);\r
+                    assertEquals(8, sheet.getRow(5).getCell((short)0).getNumericCellValue(), 0);\r
+                } else if ("Document".equals(ole.getInstanceName())){\r
+                    //creating a HWPF document \r
+                    HWPFDocument doc = new HWPFDocument(data.getData());\r
+                    String txt = doc.getRange().getParagraph(0).text();\r
+                    assertEquals("OLE embedding is thoroughly unremarkable.\r", txt);\r
+                }\r
+            }\r
+\r
+        }\r
+        assertEquals("Expected 2 OLE shapes", 2, cnt);\r
+    }\r
 }\r