]> source.dussan.org Git - poi.git/commitdiff
Support for getting OLE object data from slide show. See Bug 43247 for details.
authorYegor Kozlov <yegor@apache.org>
Sat, 8 Sep 2007 16:12:29 +0000 (16:12 +0000)
committerYegor Kozlov <yegor@apache.org>
Sat, 8 Sep 2007 16:12:29 +0000 (16:12 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@573872 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java
src/scratchpad/src/org/apache/poi/hslf/record/CString.java
src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/record/ExEmbedAtom.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjAtom.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/data/ole2-embedding-2003.ppt [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java [new file with mode: 0644]

index e41bc3d5d0b27e041b4b59dbb39c39cd892ee22d..473b8f889e2fd4e8b1165dbdd3849e37393954f3 100644 (file)
 
 package org.apache.poi.hslf;
 
-import java.util.*;
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+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 org.apache.poi.POIDocument;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogger;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.apache.poi.poifs.filesystem.DocumentEntry;
-import org.apache.poi.poifs.filesystem.DocumentInputStream;
-
-import org.apache.poi.hpsf.PropertySet;
-import org.apache.poi.hpsf.PropertySetFactory;
-import org.apache.poi.hpsf.MutablePropertySet;
-import org.apache.poi.hpsf.SummaryInformation;
-import org.apache.poi.hpsf.DocumentSummaryInformation;
-
 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.*;
+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.usermodel.ObjectData;
 import org.apache.poi.hslf.usermodel.PictureData;
+import org.apache.poi.poifs.filesystem.DocumentEntry;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
 
 /**
  * This class contains the main functionality for the Powerpoint file 
@@ -68,8 +77,11 @@ public class HSLFSlideShow extends POIDocument
 
        // Raw Pictures contained in the pictures stream
        private PictureData[] _pictures;
-       
-       /**
+
+    // Embedded objects stored in storage records in the document stream, lazily populated.
+    private ObjectData[] _objects;
+
+    /**
         * Returns the underlying POIFSFileSystem for the document
         *  that is open.
         */
@@ -507,4 +519,22 @@ public class HSLFSlideShow extends POIDocument
        public PictureData[] getPictures() {
                return _pictures;
        }
+
+    /**
+     * Gets embedded object data from the slide show.
+     *
+     * @return the embedded objects.
+     */
+    public ObjectData[] getEmbeddedObjects() {
+        if (_objects == null) {
+            List objects = new ArrayList();
+            for (int i = 0; i < _records.length; i++) {
+                if (_records[i] instanceof ExOleObjStg) {
+                    objects.add(new ObjectData((ExOleObjStg) _records[i]));
+                }
+            }
+            _objects = (ObjectData[]) objects.toArray(new ObjectData[objects.size()]);
+        }
+        return _objects;
+    }
 }
index d51bf5e0a1e82bc4689e77516a98e4f933558282..b17efc40bd42a6ec7d8586e93c11b1c75ac38c88 100644 (file)
@@ -111,4 +111,12 @@ public class CString extends RecordAtom {
                // Write out our text
                out.write(_text);
        }
+
+    /**
+     * Gets a string representation of this object, primarily for debugging.
+     * @return a string representation of this object.
+     */
+    public String toString() {
+        return getText();
+    }
 }
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
new file mode 100644 (file)
index 0000000..a021d6b
--- /dev/null
@@ -0,0 +1,188 @@
+/* ====================================================================
+   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.hslf.record;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
+
+/**
+ * This data represents an embedded object in the document.
+ *
+ * @author Daniel Noll
+ */
+public class ExEmbed extends RecordContainer {
+
+    /**
+     * Record header data.
+     */
+    private byte[] _header;
+
+    // Links to our more interesting children
+    private ExEmbedAtom embedAtom;
+    private ExOleObjAtom oleObjAtom;
+    private CString menuName;
+    private CString progId;
+    private CString clipboardName;
+
+    /**
+     * Set things up, and find our more interesting children
+     *
+     * @param source the source data as a byte array.
+     * @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) {
+        // Grab the header
+        _header = new byte[8];
+        System.arraycopy(source,start,_header,0,8);
+
+        // Find our children
+        _children = Record.findChildRecords(source,start+8,len-8);
+        findInterestingChildren();
+    }
+
+    /**
+     * Create a new ExEmbed, with blank fields
+     */
+    public ExEmbed() {
+        _header = new byte[8];
+        _children = new Record[5];
+
+        // Setup our header block
+        _header[0] = 0x0f; // We are a container record
+        LittleEndian.putShort(_header, 2, (short)getRecordType());
+
+        // Setup our child records
+        CString cs1 = new CString();
+        CString cs2 = new CString();
+        CString cs3 = new CString();
+//        cs1.setCount(0x00);
+//        cs2.setCount(0x10);
+        _children[0] = new ExEmbedAtom();
+        _children[1] = new ExOleObjAtom();
+        _children[2] = cs1;
+        _children[3] = cs2;
+        _children[4] = cs3;
+        findInterestingChildren();
+    }
+
+    /**
+     * Go through our child records, picking out the ones that are
+     * interesting, and saving those for use by the easy helper methods.
+     */
+    private void findInterestingChildren() {
+
+        // First child should be the ExHyperlinkAtom
+        if(_children[0] instanceof ExEmbedAtom) {
+            embedAtom = (ExEmbedAtom)_children[0];
+        } else {
+            logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType());
+        }
+
+        // Second child should be the ExOleObjAtom
+        if (_children[1] instanceof ExOleObjAtom) {
+            oleObjAtom = (ExOleObjAtom)_children[1];
+        } else {
+            logger.log(POILogger.ERROR, "Second child record wasn't a ExOleObjAtom, was of type " + _children[1].getRecordType());
+        }
+
+        for (int i = 2; i < _children.length; i++) {
+            if (_children[i] instanceof CString){
+                if (menuName == null) menuName = (CString)_children[i];
+                else if (progId == null) progId = (CString)_children[i];
+                else if (clipboardName == null) clipboardName = (CString)_children[i];
+            } else {
+                logger.log(POILogger.ERROR, "Record after atoms wasn't a CString, was of type " + _children[i].getRecordType());
+            }
+        }
+    }
+
+    /**
+     * Gets the {@code ExEmbedAtom}.
+     *
+     * @return the {@code ExEmbedAtom}.
+     */
+    public ExEmbedAtom getExEmbedAtom()
+    {
+        return embedAtom;
+    }
+
+    /**
+     * Gets the {@code ExOleObjAtom}.
+     *
+     * @return the {@code ExOleObjAtom}.
+     */
+    public ExOleObjAtom getExOleObjAtom()
+    {
+        return oleObjAtom;
+    }
+
+    /**
+     * Gets the name used for menus and the Links dialog box.
+     *
+     * @return the name used for menus and the Links dialog box.
+     */
+    public String getMenuName()
+    {
+        return menuName == null ? null : menuName.getText();
+    }
+
+    /**
+     * Gets the OLE Programmatic Identifier.
+     * 
+     * @return the OLE Programmatic Identifier.
+     */
+    public String getProgId()
+    {
+        return progId == null ? null : progId.getText();
+    }
+
+    /**
+     * Gets the name that appears in the paste special dialog.
+     *
+     * @return the name that appears in the paste special dialog.
+     */
+    public String getClipboardName()
+    {
+        return clipboardName == null ? null : clipboardName.getText();
+    }
+
+    /**
+     * Returns the type (held as a little endian in bytes 3 and 4)
+     * that this class handles.
+     *
+     * @return the record type.
+     */
+    public long getRecordType() {
+        return RecordTypes.ExEmbed.typeID;
+    }
+
+    /**
+     * Have the contents printer out into an OutputStream, used when
+     * writing a file back out to disk.
+     *
+     * @param out the output stream.
+     * @throws IOException if there was an error writing to the stream.
+     */
+    public void writeOut(OutputStream out) throws IOException {
+        writeOut(_header[0],_header[1],getRecordType(),_children,out);
+    }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbedAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbedAtom.java
new file mode 100644 (file)
index 0000000..d2344c4
--- /dev/null
@@ -0,0 +1,161 @@
+/* ====================================================================
+   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.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * The atom that holds metadata on a specific embedded object in the document.
+ *
+ * <!--
+ * 0    sint4    followColorScheme  This field indicates how the object follows the color scheme. Valid values are:
+ *                                  0 - doesn't follow the color scheme
+ *                                  1 - follows the entire color scheme
+ *                                  2 - follows the text and background scheme
+ *
+ * 4    bool1    cantLockServerB    Set if the embedded server can not be locked
+ * 5    bool1    noSizeToServerB    Set if don't need to send the dimension to the embedded object
+ * 6    Bool1    isTable            Set if the object is a Word table
+ * -->
+ *
+ * @author Daniel Noll
+ */
+public class ExEmbedAtom extends RecordAtom {
+
+    /**
+     * Embedded document does not follow the color scheme.
+     */
+    public static final int DOES_NOT_FOLLOW_COLOR_SCHEME = 0;
+
+    /**
+     * Embedded document follows the entire color scheme.
+     */
+    public static final int FOLLOWS_ENTIRE_COLOR_SCHEME = 1;
+
+    /**
+     * Embedded document follows the text and background scheme.
+     */
+    public static final int FOLLOWS_TEXT_AND_BACKGROUND_SCHEME = 2;
+
+    /**
+     * Record header.
+     */
+    private byte[] _header;
+
+    /**
+     * Record data.
+     */
+    private byte[] _data;
+
+    /**
+     * Constructs a brand new embedded object atom record.
+     */
+    protected ExEmbedAtom() {
+        _header = new byte[8];
+        _data = new byte[7];
+
+        LittleEndian.putShort(_header, 2, (short)getRecordType());
+        LittleEndian.putInt(_header, 4, _data.length);
+
+        // It is fine for the other values to be zero
+    }
+
+    /**
+     * Constructs the embedded object atom record from its source data.
+     *
+     * @param source the source data as a byte array.
+     * @param start the start offset into the byte array.
+     * @param len the length of the slice in the byte array.
+     */
+    protected ExEmbedAtom(byte[] source, int start, int len) {
+        // Get the header.
+        _header = new byte[8];
+        System.arraycopy(source,start,_header,0,8);
+
+        // Get the record data.
+        _data = new byte[len-8];
+        System.arraycopy(source,start+8,_data,0,len-8);
+
+        // Must be at least 4 bytes long
+        if(_data.length < 7) {
+               throw new IllegalArgumentException("The length of the data for a ExEmbedAtom must be at least 4 bytes, but was only " + _data.length);
+        }
+    }
+
+    /**
+     * Gets whether the object follows the color scheme.
+     *
+     * @return one of {@link #DOES_NOT_FOLLOW_COLOR_SCHEME},
+     *                {@link #FOLLOWS_ENTIRE_COLOR_SCHEME}, or
+     *                {@link #FOLLOWS_TEXT_AND_BACKGROUND_SCHEME}.
+     */
+    public int getFollowColorScheme() {
+        return LittleEndian.getInt(_data, 0);
+    }
+
+    /**
+     * Gets whether the embedded server cannot be locked.
+     *
+     * @return {@code true} if the embedded server cannot be locked.
+     */
+    public boolean getCantLockServerB() {
+        return _data[4] != 0;
+    }
+
+    /**
+     * Gets whether it is not required to send the dimensions to the embedded object.
+     *
+     * @return {@code true} if the embedded server does not require the object dimensions.
+     */
+    public boolean getNoSizeToServerB() {
+        return _data[5] != 0;
+    }
+
+    /**
+     * Getswhether the object is a Word table.
+     *
+     * @return {@code true} if the object is a Word table.
+     */
+    public boolean getIsTable() {
+        return _data[6] != 0;
+    }
+
+    /**
+     * Gets the record type.
+     * @return the record type.
+     */
+    public long getRecordType() {
+        return RecordTypes.ExEmbedAtom.typeID;
+    }
+
+    /**
+     * Write the contents of the record back, so it can be written
+     * to disk
+     *
+     * @param out the output stream to write to.
+     * @throws IOException if an error occurs.
+     */
+    public void writeOut(OutputStream out) throws IOException {
+        out.write(_header);
+        out.write(_data);
+    }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjAtom.java
new file mode 100644 (file)
index 0000000..ae96275
--- /dev/null
@@ -0,0 +1,213 @@
+/* ====================================================================
+   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.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Atom storing information for an OLE object.
+ *
+ * <!--
+ * offset   type    name         description
+ *
+ * 0        uint4   drawAspect   Stores whether the object can be completely seen
+ *                               (value of 1), or if only the icon is visible (value of 4).
+ *
+ * 4        sint4    type        Specifies whether the object is embedded or linked.
+ *                               0 - embedded
+ *                               1 - linked
+ *
+ * 8        sint4    objID       Unique identifier for the OLE object
+ *
+ * 2        sint4    subType     This specifies the type of ole object.
+ *                               0 - Default object
+ *                               1 - Microsoft Clipart Gallery
+ *                               2 - Microsoft Word table
+ *                               3 - Microsoft Excel
+ *                               4 - Microsoft Graph
+ *                               5 - Microsoft Organization Chart
+ *                               6 - Microsoft Equation Editor
+ *                               7 - Microsoft Wordart object
+ *                               8 - Sound
+ *                               9 - Image
+ *                               10 - PowerPoint presentation
+ *                               11 - PowerPoint slide
+ *                               12 - Microsoft Project
+ *                               13 - Microsoft Note-It Ole
+ *                               14 - Microsoft Excel chart
+ *                               15 - Media Player object
+ *
+ * 16       sint4    objStgDataRef    Reference to persist object
+ *
+ * 20       bool1    isBlank          Set if the object's image is blank
+ *           (note: KOffice has this as an int.)
+ * -->
+ *
+ * @author Daniel Noll
+ */
+public class ExOleObjAtom extends RecordAtom {
+
+    public static final int DRAW_ASPECT_VISIBLE = 1;
+    public static final int DRAW_ASPECT_ICON = 4;
+
+    public static final int TYPE_EMBEDDED = 0;
+    public static final int TYPE_LINKED = 1;
+
+    public static final int SUBTYPE_DEFAULT = 0;
+    public static final int SUBTYPE_CLIPART_GALLERY = 1;
+    public static final int SUBTYPE_WORD_TABLE = 2;
+    public static final int SUBTYPE_EXCEL = 3;
+    public static final int SUBTYPE_GRAPH = 4;
+    public static final int SUBTYPE_ORGANIZATION_CHART = 5;
+    public static final int SUBTYPE_EQUATION = 6;
+    public static final int SUBTYPE_WORDART = 7;
+    public static final int SUBTYPE_SOUND = 8;
+    public static final int SUBTYPE_IMAGE = 9;
+    public static final int SUBTYPE_POWERPOINT_PRESENTATION = 10;
+    public static final int SUBTYPE_POWERPOINT_SLIDE = 11;
+    public static final int SUBTYPE_PROJECT = 12;
+    public static final int SUBTYPE_NOTEIT = 13;
+    public static final int SUBTYPE_EXCEL_CHART = 14;
+    public static final int SUBTYPE_MEDIA_PLAYER = 15;
+
+    /**
+     * Record header.
+     */
+    private byte[] _header;
+
+    /**
+     * Record data.
+     */
+    private byte[] _data;
+
+    /**
+     * Constructs a brand new link related atom record.
+     */
+    protected ExOleObjAtom() {
+        _header = new byte[8];
+        _data = new byte[18];
+
+        LittleEndian.putShort(_header, 2, (short)getRecordType());
+        LittleEndian.putInt(_header, 4, _data.length);
+
+        // I hope it is fine for the other values to be zero.
+    }
+
+    /**
+     * Constructs the link related atom record from its
+     *  source data.
+     *
+     * @param source the source data as a byte array.
+     * @param start the start offset into the byte array.
+     * @param len the length of the slice in the byte array.
+     */
+    protected ExOleObjAtom(byte[] source, int start, int len) {
+        // Get the header.
+        _header = new byte[8];
+        System.arraycopy(source,start,_header,0,8);
+
+        // Get the record data.
+        _data = new byte[len-8];
+        System.arraycopy(source,start+8,_data,0,len-8);
+
+        // Must be at least 24 bytes long
+        if(_data.length < 24) {
+               throw new IllegalArgumentException("The length of the data for a ExOleObjAtom must be at least 24 bytes, but was only " + _data.length);
+        }
+    }
+
+    /**
+     * Gets whether the object can be completely seen, or if only the
+     * icon is visible.
+     *
+     * @return the draw aspect, one of the {@code DRAW_ASPECT_*} constants.
+     */
+    public int getDrawAspect() {
+        return LittleEndian.getInt(_data, 0);
+    }
+
+    /**
+     * Gets whether the object is embedded or linked.
+     *
+     * @return the type, one of the {@code TYPE_EMBEDDED_*} constants.
+     */
+    public int getType() {
+        return LittleEndian.getInt(_data, 4);
+    }
+
+    /**
+     * Gets the unique identifier for the OLE object.
+     *
+     * @return the object ID.
+     */
+    public int getObjID() {
+        return LittleEndian.getInt(_data, 8);
+    }
+
+    /**
+     * Gets the type of OLE object.
+     * 
+     * @return the sub-type, one of the {@code SUBTYPE_*} constants.
+     */
+    public int getSubType() {
+        return LittleEndian.getInt(_data, 12);
+    }
+
+    /**
+     * Gets the reference to the persistent object
+     *
+     * @return the reference to the persistent object, corresponds with an
+     *         {@code ExOleObjStg} storage container.
+     */
+    public int getObjStgDataRef() {
+        return LittleEndian.getInt(_data, 16);
+    }
+
+    /**
+     * Gets whether the object's image is blank.
+     *
+     * @return {@code true} if the object's image is blank.
+     */
+    public boolean getIsBlank() {
+        // Even though this is a mere boolean, KOffice's code says it's an int.
+        return LittleEndian.getInt(_data, 20) != 0;
+    }
+    
+    /**
+     * Returns the type (held as a little endian in bytes 3 and 4)
+     * that this class handles.
+     */
+    public long getRecordType() {
+        return RecordTypes.ExOleObjAtom.typeID;
+    }
+
+    /**
+     * Have the contents printer out into an OutputStream, used when
+     * writing a file back out to disk
+     * (Normally, atom classes will keep their bytes around, but
+     * non atom classes will just request the bytes from their
+     * children, then chuck on their header and return)
+     */
+    public void writeOut(OutputStream out) throws IOException {
+        out.write(_header);
+        out.write(_data);
+    }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java
new file mode 100644 (file)
index 0000000..7c47427
--- /dev/null
@@ -0,0 +1,112 @@
+/* ====================================================================
+   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.hslf.record;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.InflaterInputStream;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Storage for embedded OLE objects.
+ *
+ * @author Daniel Noll
+ */
+public class ExOleObjStg extends RecordAtom {
+    /**
+     * Record header.
+     */
+    private byte[] _header;
+
+    /**
+     * Record data.
+     */
+    private byte[] _data;
+
+    /**
+     * Constructs a new empty storage container.
+     */
+    protected ExOleObjStg() {
+        _header = new byte[8];
+        _data = new byte[0];
+
+        LittleEndian.putShort(_header, 2, (short)getRecordType());
+        LittleEndian.putInt(_header, 4, _data.length);
+    }
+
+    /**
+     * Constructs the link related atom record from its
+     *  source data.
+     *
+     * @param source the source data as a byte array.
+     * @param start the start offset into the byte array.
+     * @param len the length of the slice in the byte array.
+     */
+    protected ExOleObjStg(byte[] source, int start, int len) {
+        // Get the header.
+        _header = new byte[8];
+        System.arraycopy(source,start,_header,0,8);
+
+        // Get the record data.
+        _data = new byte[len-8];
+        System.arraycopy(source,start+8,_data,0,len-8);
+    }
+
+    /**
+     * Gets the uncompressed length of the data.
+     *
+     * @return the uncompressed length of the data.
+     */
+    public int getDataLength() {
+        return LittleEndian.getInt(_data, 0);
+    }
+
+    /**
+     * Opens an input stream which will decompress the data on the fly.
+     *
+     * @return the data input stream.
+     */
+    public InputStream getData() {
+        InputStream compressedStream = new ByteArrayInputStream(_data, 4, _data.length);
+        return new InflaterInputStream(compressedStream);
+    }
+
+    /**
+     * Gets the record type.
+     *
+     * @return the record type.
+     */
+    public long getRecordType() {
+        return RecordTypes.ExOleObjStg.typeID;
+    }
+
+    /**
+     * Write the contents of the record back, so it can be written
+     * to disk.
+     *
+     * @param out the output stream to write to.
+     * @throws IOException if an error occurs.
+     */
+    public void writeOut(OutputStream out) throws IOException {
+        out.write(_header);
+        out.write(_data);
+    }
+}
index 3c8d3aa41c9d9201fc5f9b8502723de3bbbaef19..69173bf5bb700708fd2bf57dff65466b17f193f0 100644 (file)
@@ -98,11 +98,11 @@ public class RecordTypes {
     public static final Type FontEmbeddedData = new Type(4024,null);
     public static final Type CString = new Type(4026,CString.class);
     public static final Type MetaFile = new Type(4033,null);
-    public static final Type ExOleObjAtom = new Type(4035,null);
+    public static final Type ExOleObjAtom = new Type(4035,ExOleObjAtom.class);
     public static final Type SrKinsoku = new Type(4040,null);
     public static final Type HandOut = new Type(4041,null);
-    public static final Type ExEmbed = new Type(4044,null);
-    public static final Type ExEmbedAtom = new Type(4045,null);
+    public static final Type ExEmbed = new Type(4044,ExEmbed.class);
+    public static final Type ExEmbedAtom = new Type(4045,ExEmbedAtom.class);
     public static final Type ExLink = new Type(4046,null);
     public static final Type BookmarkEntityAtom = new Type(4048,null);
     public static final Type ExLinkAtom = new Type(4049,null);
@@ -136,7 +136,7 @@ public class RecordTypes {
     public static final Type ExCDAudio = new Type(4110,null);
     public static final Type ExWAVAudioEmbedded = new Type(4111,null);
     public static final Type ExWAVAudioLink = new Type(4112,null);
-    public static final Type ExOleObjStg = new Type(4113,null);
+    public static final Type ExOleObjStg = new Type(4113,ExOleObjStg.class);
     public static final Type ExCDAudioAtom = new Type(4114,null);
     public static final Type ExWAVAudioEmbeddedAtom = new Type(4115,null);
     public static final Type AnimationInfoAtom = new Type(4116,null);
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java
new file mode 100644 (file)
index 0000000..66b4f03
--- /dev/null
@@ -0,0 +1,51 @@
+/* ====================================================================
+   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.hslf.usermodel;
+
+import java.io.InputStream;
+
+import org.apache.poi.hslf.record.ExOleObjStg;
+
+/**
+ * A class that represents object data embedded in a slide show.
+ *
+ * @author Daniel Noll
+ */
+public class ObjectData {
+    /**
+     * The record that contains the object data.
+     */
+    private ExOleObjStg storage;
+
+    /**
+     * Creates the object data wrapping the record that contains the object data.
+     *
+     * @param storage the record that contains the object data.
+     */
+    public ObjectData(ExOleObjStg storage) {
+        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() {
+        return storage.getData();
+    }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/ole2-embedding-2003.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/ole2-embedding-2003.ppt
new file mode 100644 (file)
index 0000000..506888f
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/ole2-embedding-2003.ppt differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java
new file mode 100644 (file)
index 0000000..7be6f9d
--- /dev/null
@@ -0,0 +1,62 @@
+\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
+\r
+\r
+package org.apache.poi.hslf.model;\r
+\r
+import java.io.*;\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
+\r
+import junit.framework.TestCase;\r
+\r
+public class TestOleEmbedding extends TestCase\r
+{\r
+    /**\r
+     * Tests support for OLE objects.\r
+     *\r
+     * @throws Exception if an error occurs.\r
+     */\r
+    public void testOleEmbedding2003() throws Exception\r
+    {\r
+        String dirname = System.getProperty("HSLF.testdata.path");\r
+        File file = new File(dirname, "ole2-embedding-2003.ppt");\r
+        HSLFSlideShow slideShow = new HSLFSlideShow(new FileInputStream(file));\r
+        try\r
+        {\r
+            // Placeholder EMFs for clients that don't support the OLE components.\r
+            PictureData[] pictures = slideShow.getPictures();\r
+            assertEquals("Should be two pictures", 2, pictures.length);\r
+            //assertDigestEquals("Wrong data for picture 1", "8d1fbadf4814f321bb1ccdd056e3c788", pictures[0].getData());\r
+            //assertDigestEquals("Wrong data for picture 2", "987a698e83559cf3d38a0deeba1cc63b", pictures[1].getData());\r
+\r
+            // Actual embedded objects.\r
+            ObjectData[] objects = slideShow.getEmbeddedObjects();\r
+            assertEquals("Should be two objects", 2, objects.length);\r
+            //assertDigestEquals("Wrong data for objecs 1", "0d1fcc61a83de5c4894dc0c88e9a019d", objects[0].getData());\r
+            //assertDigestEquals("Wrong data for object 2", "b323604b2003a7299c77c2693b641495", objects[1].getData());\r
+        }\r
+        finally\r
+        {\r
+            slideShow.close();\r
+        }\r
+    }\r
+}\r