You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2013/10/13 09:39:41 UTC

svn commit: r1531623 - in /poi/trunk/src: java/org/apache/poi/hpsf/ java/org/apache/poi/hssf/record/ java/org/apache/poi/hssf/usermodel/ java/org/apache/poi/poifs/filesystem/ testcases/org/apache/poi/hssf/usermodel/

Author: yegor
Date: Sun Oct 13 07:39:40 2013
New Revision: 1531623

URL: http://svn.apache.org/r1531623
Log:
Bugzilla 55578 - Support embedding OLE1.0 packages in HSSF

Added:
    poi/trunk/src/java/org/apache/poi/hssf/record/FtCfSubRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java
Modified:
    poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java
    poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java
    poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestOLE2Embeding.java

Modified: poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java (original)
+++ poi/trunk/src/java/org/apache/poi/hpsf/ClassID.java Sun Oct 13 07:39:40 2013
@@ -30,7 +30,12 @@ import org.apache.poi.util.HexDump;
  */
 public class ClassID
 {
-
+    public static final ClassID OLE10_PACKAGE = new ClassID("{0003000C-0000-0000-C000-000000000046}");
+    public static final ClassID PPT_SHOW = new ClassID("{64818D10-4F9B-11CF-86EA-00AA00B929E8}");
+    public static final ClassID XLS_WORKBOOK = new ClassID("{00020841-0000-0000-C000-000000000046}");
+    public static final ClassID TXT_ONLY = new ClassID("{5e941d80-bf96-11cd-b579-08002b30bfeb}"); // ???
+	
+	
     /**
      * <p>The bytes making out the class ID in correct order,
      * i.e. big-endian.</p>
@@ -64,6 +69,20 @@ public class ClassID
     }
 
 
+    /**
+     * <p>Creates a {@link ClassID} from a human-readable representation of the Class ID in standard 
+     * format <code>"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"</code>.</p>
+     * 
+     * @param externalForm representation of the Class ID represented by this object.
+     */
+    public ClassID(String externalForm) {
+    	bytes = new byte[LENGTH];
+        String clsStr = externalForm.replaceAll("[{}-]", "");
+        for (int i=0; i<clsStr.length(); i+=2) {
+        	bytes[i/2] = (byte)Integer.parseInt(clsStr.substring(i, i+2), 16);
+        }
+    }
+    
 
     /** <p>The number of bytes occupied by this object in the byte
      * stream.</p> */

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java Sun Oct 13 07:39:40 2013
@@ -64,7 +64,7 @@ public final class EmbeddedObjectRefSubR
 
 
 	// currently for testing only - needs review
-	EmbeddedObjectRefSubRecord() {
+	public EmbeddedObjectRefSubRecord() {
 		field_2_unknownFormulaData = new byte[] { 0x02, 0x6C, 0x6A, 0x16, 0x01, }; // just some sample data.  These values vary a lot
 		field_6_unknown = EMPTY_BYTE_ARRAY;
 		field_4_ole_classname = null;
@@ -334,4 +334,16 @@ public final class EmbeddedObjectRefSubR
 		sb.append("[/ftPictFmla]");
 		return sb.toString();
 	}
+	
+	public void setUnknownFormulaData(byte[] formularData) {
+		field_2_unknownFormulaData = formularData;
+	}
+	
+	public void setOleClassname(String oleClassname) {
+		field_4_ole_classname = oleClassname;
+	}
+	
+	public void setStorageId(int storageId) {
+		field_5_stream_id = storageId;
+	}
 }

Added: poi/trunk/src/java/org/apache/poi/hssf/record/FtCfSubRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/FtCfSubRecord.java?rev=1531623&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/FtCfSubRecord.java (added)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/FtCfSubRecord.java Sun Oct 13 07:39:40 2013
@@ -0,0 +1,113 @@
+/* ====================================================================
+   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.hssf.record;
+
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
+
+
+/**
+ * The FtCf structure specifies the clipboard format of the picture-type Obj record containing this FtCf.
+ */
+public final class FtCfSubRecord extends SubRecord {
+    public final static short sid = 0x07;
+    public final static short length = 0x02;
+    
+    /**
+     * Specifies the format of the picture is an enhanced metafile.
+     */
+    public static short METAFILE_BIT    = (short)0x0002;
+
+    /**
+     * Specifies the format of the picture is a bitmap.
+     */
+    public static short BITMAP_BIT      = (short)0x0009;
+    
+    /**
+     * Specifies the picture is in an unspecified format that is
+     * neither and enhanced metafile nor a bitmap.
+     */
+    public static short UNSPECIFIED_BIT = (short)0xFFFF;
+    
+    private short flags = 0;
+
+    /**
+     * Construct a new <code>FtPioGrbitSubRecord</code> and
+     * fill its data with the default values
+     */
+    public FtCfSubRecord() {
+    }
+
+    public FtCfSubRecord(LittleEndianInput in, int size) {
+        if (size != length) {
+            throw new RecordFormatException("Unexpected size (" + size + ")");
+        }
+        flags = in.readShort();
+    }
+
+    /**
+     * Convert this record to string.
+     * Used by BiffViewer and other utilities.
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("[FtCf ]\n");
+        buffer.append("  size     = ").append(length).append("\n");
+        buffer.append("  flags    = ").append(HexDump.toHex(flags)).append("\n");
+        buffer.append("[/FtCf ]\n");
+        return buffer.toString();
+    }
+
+    /**
+     * Serialize the record data into the supplied array of bytes
+     *
+     * @param out the stream to serialize into
+     */
+    public void serialize(LittleEndianOutput out) {
+        out.writeShort(sid);
+        out.writeShort(length);
+        out.writeShort(flags);
+    }
+
+ protected int getDataSize() {
+        return length;
+    }
+
+    /**
+     * @return id of this record.
+     */
+    public short getSid()
+    {
+        return sid;
+    }
+
+    public Object clone() {
+        FtCfSubRecord rec = new FtCfSubRecord();
+        rec.flags = this.flags;
+        return rec;
+    }
+
+ public short getFlags() {
+   return flags;
+ }
+
+ public void setFlags(short flags) {
+   this.flags = flags;
+ }
+}
\ No newline at end of file

Added: poi/trunk/src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java?rev=1531623&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java (added)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java Sun Oct 13 07:39:40 2013
@@ -0,0 +1,167 @@
+/* ====================================================================
+   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.hssf.record;
+
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
+
+
+/**
+ * This structure appears as part of an Obj record that represents image display properties.
+ */
+public final class FtPioGrbitSubRecord extends SubRecord {
+    public final static short sid = 0x08;
+    public final static short length = 0x02;
+    
+    /**
+     * A bit that specifies whether the picture's aspect ratio is preserved when rendered in 
+     * different views (Normal view, Page Break Preview view, Page Layout view and printing).
+     */
+    public static int AUTO_PICT_BIT    = 1 << 0;
+
+    /**
+     * A bit that specifies whether the pictFmla field of the Obj record that contains 
+     * this FtPioGrbit specifies a DDE reference.
+     */
+    public static int DDE_BIT          = 1 << 1;
+    
+    /**
+     * A bit that specifies whether this object is expected to be updated on print to
+     * reflect the values in the cell associated with the object.
+     */
+    public static int PRINT_CALC_BIT   = 1 << 2;
+
+    /**
+     * A bit that specifies whether the picture is displayed as an icon.
+     */
+    public static int ICON_BIT         = 1 << 3;
+    
+    /**
+     * A bit that specifies whether this object is an ActiveX control.
+     * It MUST NOT be the case that both fCtl and fDde are equal to 1.
+     */
+    public static int CTL_BIT          = 1 << 4;
+    
+    /**
+     * A bit that specifies whether the object data are stored in an
+     * embedding storage (= 0) or in the controls stream (ctls) (= 1).
+     */
+    public static int PRSTM_BIT        = 1 << 5;
+    
+    /**
+     * A bit that specifies whether this is a camera picture.
+     */
+    public static int CAMERA_BIT       = 1 << 7;
+    
+    /**
+     * A bit that specifies whether this picture's size has been explicitly set.
+     * 0 = picture size has been explicitly set, 1 = has not been set
+     */
+    public static int DEFAULT_SIZE_BIT = 1 << 8;
+    
+    /**
+     * A bit that specifies whether the OLE server for the object is called
+     * to load the object's data automatically when the parent workbook is opened.
+     */
+    public static int AUTO_LOAD_BIT    = 1 << 9;
+
+    
+    private short flags = 0;
+
+    /**
+     * Construct a new <code>FtPioGrbitSubRecord</code> and
+     * fill its data with the default values
+     */
+    public FtPioGrbitSubRecord() {
+    }
+
+    public FtPioGrbitSubRecord(LittleEndianInput in, int size) {
+        if (size != length) {
+            throw new RecordFormatException("Unexpected size (" + size + ")");
+        }
+        flags = in.readShort();
+    }
+
+    /**
+     * Use one of the bitmasks MANUAL_ADVANCE_BIT ... CURSOR_VISIBLE_BIT
+     * @param bitmask
+     * @param enabled
+     */
+    public void setFlagByBit(int bitmask, boolean enabled) {
+        if (enabled) {
+            flags |= bitmask;
+        } else {
+            flags &= (0xFFFF ^ bitmask);
+        }
+    }    
+    
+    public boolean getFlagByBit(int bitmask) {
+        return ((flags & bitmask) != 0);
+    }
+    
+    /**
+     * Convert this record to string.
+     * Used by BiffViewer and other utilities.
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("[FtPioGrbit ]\n");
+        buffer.append("  size     = ").append(length).append("\n");
+        buffer.append("  flags    = ").append(HexDump.toHex(flags)).append("\n");
+        buffer.append("[/FtPioGrbit ]\n");
+        return buffer.toString();
+    }
+
+    /**
+     * Serialize the record data into the supplied array of bytes
+     *
+     * @param out the stream to serialize into
+     */
+    public void serialize(LittleEndianOutput out) {
+        out.writeShort(sid);
+        out.writeShort(length);
+        out.writeShort(flags);
+    }
+
+ protected int getDataSize() {
+        return length;
+    }
+
+    /**
+     * @return id of this record.
+     */
+    public short getSid()
+    {
+        return sid;
+    }
+
+    public Object clone() {
+        FtPioGrbitSubRecord rec = new FtPioGrbitSubRecord();
+        rec.flags = this.flags;
+        return rec;
+    }
+
+ public short getFlags() {
+   return flags;
+ }
+
+ public void setFlags(short flags) {
+   this.flags = flags;
+ }
+}
\ No newline at end of file

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SubRecord.java Sun Oct 13 07:39:40 2013
@@ -59,6 +59,10 @@ public abstract class SubRecord {
 				return new LbsDataSubRecord(in, secondUShort, cmoOt);
             case FtCblsSubRecord.sid:
                 return new FtCblsSubRecord(in, secondUShort);
+            case FtPioGrbitSubRecord.sid:
+            	return new FtPioGrbitSubRecord(in, secondUShort);
+            case FtCfSubRecord.sid:
+            	return new FtCfSubRecord(in, secondUShort);
 		}
 		return new UnknownSubRecord(in, sid, secondUShort);
 	}

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java Sun Oct 13 07:39:40 2013
@@ -17,27 +17,35 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import java.io.FileNotFoundException;
 import java.util.*;
 
 import org.apache.poi.ddf.*;
 import org.apache.poi.hssf.model.DrawingManager2;
+import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
+import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
+import org.apache.poi.hssf.record.EndSubRecord;
 import org.apache.poi.hssf.record.EscherAggregate;
+import org.apache.poi.hssf.record.FtCfSubRecord;
+import org.apache.poi.hssf.record.FtPioGrbitSubRecord;
 import org.apache.poi.hssf.record.NoteRecord;
+import org.apache.poi.hssf.record.ObjRecord;
 import org.apache.poi.hssf.util.CellReference;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.ss.usermodel.Chart;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-import org.apache.poi.util.StringUtil;
-import org.apache.poi.util.Internal;
-import org.apache.poi.ss.usermodel.Drawing;
 import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.StringUtil;
 
 /**
  * The patriarch is the toplevel container for shapes in a sheet.  It does
  * little other than act as a container for other shapes and groups.
  */
 public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
-    private static POILogger log = POILogFactory.getLogger(HSSFPatriarch.class);
+    // private static POILogger log = POILogFactory.getLogger(HSSFPatriarch.class);
     private final List<HSSFShape> _shapes = new ArrayList<HSSFShape>();
 
     private final EscherSpgrRecord _spgrRecord;
@@ -194,6 +202,87 @@ public final class HSSFPatriarch impleme
     }
 
     /**
+     * Adds a new OLE Package Shape 
+     * 
+     * @param anchor       the client anchor describes how this picture is
+     *                     attached to the sheet.
+     * @param storageId    the storageId returned by {@Link HSSFWorkbook.addOlePackage}
+     * @param pictureIndex the index of the picture (used as preview image) in the
+     *                     workbook collection of pictures.
+     *
+     * @return newly created shape
+     */
+    public HSSFObjectData createObjectData(HSSFClientAnchor anchor, int storageId, int pictureIndex) {
+        ObjRecord obj = new ObjRecord();
+
+        CommonObjectDataSubRecord ftCmo = new CommonObjectDataSubRecord();
+        ftCmo.setObjectType(CommonObjectDataSubRecord.OBJECT_TYPE_PICTURE);
+        // ftCmo.setObjectId(oleShape.getShapeId()); ... will be set by onCreate(...)
+        ftCmo.setLocked(true);
+        ftCmo.setPrintable(true);
+        ftCmo.setAutofill(true);
+        ftCmo.setAutoline(true);
+        ftCmo.setReserved1(0);
+        ftCmo.setReserved2(0);
+        ftCmo.setReserved3(0);
+        obj.addSubRecord(ftCmo);
+        
+        // FtCf (pictFormat) 
+        FtCfSubRecord ftCf = new FtCfSubRecord();
+        HSSFPictureData pictData = getSheet().getWorkbook().getAllPictures().get(pictureIndex-1);
+        switch (pictData.getFormat()) {
+	        case HSSFWorkbook.PICTURE_TYPE_WMF:
+	        case HSSFWorkbook.PICTURE_TYPE_EMF:
+	        	// this needs patch #49658 to be applied to actually work 
+	            ftCf.setFlags(FtCfSubRecord.METAFILE_BIT);
+	            break;
+	        case HSSFWorkbook.PICTURE_TYPE_DIB:
+	        case HSSFWorkbook.PICTURE_TYPE_PNG:
+	        case HSSFWorkbook.PICTURE_TYPE_JPEG:
+	        case HSSFWorkbook.PICTURE_TYPE_PICT:
+	            ftCf.setFlags(FtCfSubRecord.BITMAP_BIT);
+	            break;
+        }
+        obj.addSubRecord(ftCf);
+        // FtPioGrbit (pictFlags)
+        FtPioGrbitSubRecord ftPioGrbit = new FtPioGrbitSubRecord();
+        ftPioGrbit.setFlagByBit(FtPioGrbitSubRecord.AUTO_PICT_BIT, true);
+        obj.addSubRecord(ftPioGrbit);
+        
+        EmbeddedObjectRefSubRecord ftPictFmla = new EmbeddedObjectRefSubRecord();
+        ftPictFmla.setUnknownFormulaData(new byte[]{2, 0, 0, 0, 0});
+        ftPictFmla.setOleClassname("Paket");
+        ftPictFmla.setStorageId(storageId);
+        
+        obj.addSubRecord(ftPictFmla);
+        obj.addSubRecord(new EndSubRecord());
+
+        String entryName = "MBD"+HexDump.toHex(storageId);
+        DirectoryEntry oleRoot;
+        try {
+            DirectoryNode dn = _sheet.getWorkbook().getRootDirectory();
+        	if (dn == null) throw new FileNotFoundException();
+        	oleRoot = (DirectoryEntry)dn.getEntry(entryName);
+        } catch (FileNotFoundException e) {
+        	throw new IllegalStateException("trying to add ole shape without actually adding data first - use HSSFWorkbook.addOlePackage first", e);
+        }
+        
+        // create picture shape, which need to be minimal modified for oleshapes
+        HSSFPicture shape = new HSSFPicture(null, anchor);
+        shape.setPictureIndex(pictureIndex);
+        EscherContainerRecord spContainer = shape.getEscherContainer();
+        EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
+        spRecord.setFlags(spRecord.getFlags() |  EscherSpRecord.FLAG_OLESHAPE);
+        
+        HSSFObjectData oleShape = new HSSFObjectData(spContainer, obj, oleRoot); 
+        addShape(oleShape);
+        onCreate(oleShape);
+        
+        
+        return oleShape;
+    }
+    
+    /**
      * Creates a polygon
      *
      * @param anchor the client anchor describes how this group is attached

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java Sun Oct 13 07:39:40 2013
@@ -18,15 +18,19 @@
 package org.apache.poi.hssf.usermodel;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 
 import org.apache.commons.codec.digest.DigestUtils;
@@ -36,6 +40,7 @@ import org.apache.poi.ddf.EscherBitmapBl
 import org.apache.poi.ddf.EscherBlipRecord;
 import org.apache.poi.ddf.EscherMetafileBlip;
 import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.hssf.OldExcelFormatException;
 import org.apache.poi.hssf.model.DrawingManager2;
 import org.apache.poi.hssf.model.HSSFFormulaParser;
@@ -46,7 +51,11 @@ import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
 import org.apache.poi.hssf.record.common.UnicodeString;
 import org.apache.poi.hssf.util.CellReference;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.EntryUtils;
+import org.apache.poi.poifs.filesystem.FilteringDirectoryNode;
+import org.apache.poi.poifs.filesystem.Ole10Native;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.ss.formula.FormulaShifter;
 import org.apache.poi.ss.formula.FormulaType;
@@ -57,10 +66,7 @@ import org.apache.poi.ss.formula.udf.UDF
 import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.WorkbookUtil;
-import org.apache.poi.util.Configurator;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.poi.util.*;
 
 
 /**
@@ -1190,15 +1196,15 @@ public final class HSSFWorkbook extends 
 
         if (preserveNodes) {
             // Don't write out the old Workbook, we'll be doing our new one
-            excepts.add("Workbook");
             // If the file had an "incorrect" name for the workbook stream,
             // don't write the old one as we'll use the correct name shortly
-            for (String wrongName : WORKBOOK_DIR_ENTRY_NAMES) {
-               excepts.add(wrongName);
-            }
+        	excepts.addAll(Arrays.asList(WORKBOOK_DIR_ENTRY_NAMES));
 
             // Copy over all the other nodes to our new poifs
-            copyNodes(this.directory, fs.getRoot(), excepts);
+            EntryUtils.copyNodes(
+                    new FilteringDirectoryNode(this.directory, excepts)
+                    , new FilteringDirectoryNode(fs.getRoot(), excepts)
+            );
 
             // YK: preserve StorageClsid, it is important for embedded workbooks,
             // see Bugzilla 47920
@@ -1623,7 +1629,7 @@ public final class HSSFWorkbook extends 
     	        break;
         }
 
-        blipRecord.setRecordId( (short) ( EscherBitmapBlip.RECORD_ID_START + format ) );
+        blipRecord.setRecordId((short) (EscherBitmapBlip.RECORD_ID_START + format));
         switch (format)
         {
             case PICTURE_TYPE_EMF:
@@ -1713,6 +1719,65 @@ public final class HSSFWorkbook extends 
 
     }
 
+    protected static Map<String,ClassID> getOleMap() {
+    	Map<String,ClassID> olemap = new HashMap<String,ClassID>();
+    	olemap.put("PowerPoint Document", ClassID.PPT_SHOW);
+    	for (String str : WORKBOOK_DIR_ENTRY_NAMES) {
+    		olemap.put(str, ClassID.XLS_WORKBOOK);
+    	}
+    	// ... to be continued
+    	return olemap;
+    }
+    
+    public int addOlePackage(POIFSFileSystem poiData, String label, String fileName, String command)
+    throws IOException {
+    	DirectoryNode root = poiData.getRoot();
+    	Map<String,ClassID> olemap = getOleMap();
+    	for (Map.Entry<String,ClassID> entry : olemap.entrySet()) {
+    		if (root.hasEntry(entry.getKey())) {
+    			root.setStorageClsid(entry.getValue());
+    			break;
+    		}
+    	}
+    	
+    	ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    	poiData.writeFilesystem(bos);
+        return addOlePackage(bos.toByteArray(), label, fileName, command);
+    }
+    
+    public int addOlePackage(byte[] oleData, String label, String fileName, String command)
+    throws IOException {
+    	// check if we were created by POIFS otherwise create a new dummy POIFS for storing the package data
+    	if (directory == null) {
+    		directory = new POIFSFileSystem().getRoot();
+    		preserveNodes = true;
+    	}
+    	
+        // get free MBD-Node
+        int storageId = 0;
+        DirectoryEntry oleDir = null;
+        do {
+            String storageStr = "MBD"+ HexDump.toHex(++storageId);
+            if (!directory.hasEntry(storageStr)) {
+                oleDir = directory.createDirectory(storageStr);
+                oleDir.setStorageClsid(ClassID.OLE10_PACKAGE);
+            }
+        } while (oleDir == null);
+    	
+        // the following data was taken from an example libre office document
+        // beside this "\u0001Ole" record there were several other records, e.g. CompObj,
+        // OlePresXXX, but it seems, that they aren't neccessary
+        byte oleBytes[] = { 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+        oleDir.createDocument("\u0001Ole", new ByteArrayInputStream(oleBytes));
+        
+        Ole10Native oleNative = new Ole10Native(label, fileName, command, oleData);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        oleNative.writeOut(bos);
+        oleDir.createDocument(Ole10Native.OLE10_NATIVE, new ByteArrayInputStream(bos.toByteArray()));
+        
+    	return storageId;
+    }
+    
     /**
      * Is the workbook protected with a password (not encrypted)?
      */

Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java Sun Oct 13 07:39:40 2013
@@ -41,8 +41,10 @@ public class EntryUtils
         DirectoryEntry newTarget = null;
         if ( entry.isDirectoryEntry() )
         {
+        	DirectoryEntry dirEntry = (DirectoryEntry)entry;
             newTarget = target.createDirectory( entry.getName() );
-            Iterator<Entry> entries = ( (DirectoryEntry) entry ).getEntries();
+            newTarget.setStorageClsid( dirEntry.getStorageClsid() );
+            Iterator<Entry> entries = dirEntry.getEntries();
 
             while ( entries.hasNext() )
             {

Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java Sun Oct 13 07:39:40 2013
@@ -14,14 +14,16 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-
-package org.apache.poi.poifs.filesystem;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-import org.apache.poi.util.HexDump;
-import org.apache.poi.util.LittleEndian;
+
+package org.apache.poi.poifs.filesystem;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.StringUtil;
 
@@ -29,27 +31,27 @@ import org.apache.poi.util.StringUtil;
  * Represents an Ole10Native record which is wrapped around certain binary
  * files being embedded in OLE2 documents.
  *
- * @author Rainer Schwarze
- */
-public class Ole10Native {
-  // (the fields as they appear in the raw record:)
-  private final int totalSize;                // 4 bytes, total size of record not including this field
-  private short flags1;                // 2 bytes, unknown, mostly [02 00]
-  private final String label;                // ASCIIZ, stored in this field without the terminating zero
-  private final String fileName;        // ASCIIZ, stored in this field without the terminating zero
-  private short flags2;                // 2 bytes, unknown, mostly [00 00]
-  // private byte unknown1Length;	// 1 byte, specifying the length of the following byte array (unknown1)
-  private byte[] unknown1;        // see below
-  private byte[] unknown2;        // 3 bytes, unknown, mostly [00 00 00]
-  private final String command;                // ASCIIZ, stored in this field without the terminating zero
-  private final int dataSize;                // 4 bytes (if space), size of following buffer
-  private final byte[] dataBuffer;        // varying size, the actual native data
-  private short flags3;                // some final flags? or zero terminators?, sometimes not there
-  public static final String OLE10_NATIVE = "\u0001Ole10Native";
-
-  /**
-   * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
-   * to include a stream &quot;{01}Ole10Native&quot; which contains the actual
+ * @author Rainer Schwarze
+ */
+public class Ole10Native {
+
+  public static final String OLE10_NATIVE = "\u0001Ole10Native";
+  protected static final String ISO1 = "ISO-8859-1";
+
+  // (the fields as they appear in the raw record:)
+  private int totalSize;             // 4 bytes, total size of record not including this field
+  private short flags1 = 2;          // 2 bytes, unknown, mostly [02 00]
+  private String label;              // ASCIIZ, stored in this field without the terminating zero
+  private String fileName;           // ASCIIZ, stored in this field without the terminating zero
+  private short flags2 = 0;          // 2 bytes, unknown, mostly [00 00]
+  private short unknown1 = 3;        // see below
+  private String command;            // ASCIIZ, stored in this field without the terminating zero
+  private byte[] dataBuffer;         // varying size, the actual native data
+  private short flags3 = 0;          // some final flags? or zero terminators?, sometimes not there
+
+  /**
+   * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
+   * to include a stream &quot;{01}Ole10Native&quot; which contains the actual
    * data relevant for this class.
    *
    * @param poifs POI Filesystem object
@@ -87,12 +89,22 @@ public class Ole10Native {
      directory.createDocumentInputStream(nativeEntry).read(data);
 
      return new Ole10Native(data, 0, plain);
-  }
-  
-  /**
-   * Creates an instance and fills the fields based on the data in the given buffer.
-   *
-   * @param data   The buffer containing the Ole10Native record
+  }
+  
+  /**
+   * Creates an instance and fills the fields based on ... the fields
+   */
+  public Ole10Native(String label, String filename, String command, byte[] data) {
+	  setLabel(label);
+	  setFileName(filename);
+	  setCommand(command);
+	  setDataBuffer(data);
+  }
+  
+  /**
+   * Creates an instance and fills the fields based on the data in the given buffer.
+   *
+   * @param data   The buffer containing the Ole10Native record
    * @param offset The start offset of the record in the buffer
    * @throws Ole10NativeException on invalid or unexcepted data format
    */
@@ -117,61 +129,57 @@ public class Ole10Native {
     totalSize = LittleEndian.getInt(data, ofs);
     ofs += LittleEndianConsts.INT_SIZE;
 
-    if (plain) {
-      dataBuffer = new byte[totalSize-4];
-      System.arraycopy(data, 4, dataBuffer, 0, dataBuffer.length);
-      dataSize = totalSize - 4;
-      
-      byte[] oleLabel = new byte[8];
-      System.arraycopy(dataBuffer, 0, oleLabel, 0, Math.min(dataBuffer.length, 8));
+    if (plain) {
+      dataBuffer = new byte[totalSize-4];
+      System.arraycopy(data, 4, dataBuffer, 0, dataBuffer.length);
+      // int dataSize = totalSize - 4;
+      
+      byte[] oleLabel = new byte[8];
+      System.arraycopy(dataBuffer, 0, oleLabel, 0, Math.min(dataBuffer.length, 8));
       label = "ole-"+ HexDump.toHex(oleLabel);
       fileName = label;
       command = label;
-    } else {
-      flags1 = LittleEndian.getShort(data, ofs);
-      ofs += LittleEndianConsts.SHORT_SIZE;
-      int len = getStringLength(data, ofs);
-      label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
-      ofs += len;
-      len = getStringLength(data, ofs);
-      fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
-      ofs += len;
-      flags2 = LittleEndian.getShort(data, ofs);
-      ofs += LittleEndianConsts.SHORT_SIZE;
-      len = LittleEndian.getUByte(data, ofs);
-      unknown1 = new byte[len];
-      ofs += len;
-      len = 3;
-      unknown2 = new byte[len];
-      ofs += len;
-      len = getStringLength(data, ofs);
-      command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
-      ofs += len;
-
-      if (totalSize + LittleEndianConsts.INT_SIZE - ofs > LittleEndianConsts.INT_SIZE) {
-        dataSize = LittleEndian.getInt(data, ofs);
-        ofs += LittleEndianConsts.INT_SIZE;
-
-        if (dataSize > totalSize || dataSize<0) {
-          throw new Ole10NativeException("Invalid Ole10Native");
-        }
-
-        dataBuffer = new byte[dataSize];
-        System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
-        ofs += dataSize;
-
-        if (unknown1.length > 0) {
-          flags3 = LittleEndian.getShort(data, ofs);
-          ofs += LittleEndianConsts.SHORT_SIZE;
-        } else {
-          flags3 = 0;
-        }
-      } else {
-        throw new Ole10NativeException("Invalid Ole10Native");
-      }
-    }
-  }
-
+    } else {
+      flags1 = LittleEndian.getShort(data, ofs);
+      ofs += LittleEndianConsts.SHORT_SIZE;
+      
+      int len = getStringLength(data, ofs);
+      label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
+      ofs += len;
+      
+      len = getStringLength(data, ofs);
+      fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
+      ofs += len;
+      
+      flags2 = LittleEndian.getShort(data, ofs);
+      ofs += LittleEndianConsts.SHORT_SIZE;
+      
+      unknown1 = LittleEndian.getShort(data, ofs);
+      ofs += LittleEndianConsts.SHORT_SIZE;
+
+      len = LittleEndian.getInt(data, ofs);
+      ofs += LittleEndianConsts.INT_SIZE;
+
+      command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
+      ofs += len;
+      
+      if (totalSize < ofs) {
+          throw new Ole10NativeException("Invalid Ole10Native");
+      }
+
+      int dataSize = LittleEndian.getInt(data, ofs);
+      ofs += LittleEndianConsts.INT_SIZE;
+
+      if (dataSize < 0 || totalSize - (ofs - LittleEndianConsts.INT_SIZE) < dataSize) {
+          throw new Ole10NativeException("Invalid Ole10Native");
+      }
+      
+      dataBuffer = new byte[dataSize];
+      System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
+      ofs += dataSize;
+    }
+  }
+
   /*
    * Helper - determine length of zero terminated string (ASCIIZ).
    */
@@ -234,26 +242,17 @@ public class Ole10Native {
 
   /**
    * Returns unknown1 field - currently unknown.
-   *
-   * @return the unknown1
-   */
-  public byte[] getUnknown1() {
-    return unknown1;
-  }
-
-  /**
-   * Returns the unknown2 field - currently being a byte[3] - mostly {0, 0, 0}.
-   *
-   * @return the unknown2
-   */
-  public byte[] getUnknown2() {
-    return unknown2;
-  }
-
-  /**
-   * Returns the command field - usually the name of the file being embedded
-   * including the full path, may be a command specified during embedding the file.
-   *
+   *
+   * @return the unknown1
+   */
+  public short getUnknown1() {
+    return unknown1;
+  }
+
+  /**
+   * Returns the command field - usually the name of the file being embedded
+   * including the full path, may be a command specified during embedding the file.
+   *
    * @return the command
    */
   public String getCommand() {
@@ -265,13 +264,13 @@ public class Ole10Native {
    * embedded. To be sure, that no data has been embedded, check whether
    * {@link #getDataBuffer()} returns <code>null</code>.
    *
-   * @return the dataSize
-   */
-  public int getDataSize() {
-    return dataSize;
-  }
-
-  /**
+   * @return the dataSize
+   */
+  public int getDataSize() {
+    return dataBuffer.length;
+  }
+
+  /**
    * Returns the buffer containing the embedded file's data, or <code>null</code>
    * if no data was embedded. Note that an embedding may provide information about
    * the data, but the actual data is not included. (So label, filename etc. are
@@ -288,7 +287,89 @@ public class Ole10Native {
    *
    * @return the flags3
    */
-  public short getFlags3() {
-    return flags3;
-  }
-}
+  public short getFlags3() {
+    return flags3;
+  }
+
+  /**
+   * Have the contents printer out into an OutputStream, used when writing a
+   * file back out to disk (Normally, atom classes will keep their bytes
+   * around, but non atom classes will just request the bytes from their
+   * children, then chuck on their header and return)
+   */
+  public void writeOut(OutputStream out) throws IOException {
+      byte intbuf[] = new byte[LittleEndianConsts.INT_SIZE];
+      byte shortbuf[] = new byte[LittleEndianConsts.SHORT_SIZE];
+
+      ByteArrayOutputStream bos = new ByteArrayOutputStream();
+      bos.write(intbuf); // total size, will be determined later ..
+
+      LittleEndian.putShort(shortbuf, 0, getFlags1());
+      bos.write(shortbuf);
+
+      bos.write(getLabel().getBytes(ISO1));
+      bos.write(0);
+
+      bos.write(getFileName().getBytes(ISO1));
+      bos.write(0);
+
+      LittleEndian.putShort(shortbuf, 0, getFlags2());
+      bos.write(shortbuf);
+
+      LittleEndian.putShort(shortbuf, 0, getUnknown1());
+      bos.write(shortbuf);
+
+      LittleEndian.putInt(intbuf, 0, getCommand().length()+1);
+      bos.write(intbuf);
+
+      bos.write(getCommand().getBytes(ISO1));
+      bos.write(0);
+
+      LittleEndian.putInt(intbuf, 0, getDataBuffer().length);
+      bos.write(intbuf);
+
+      bos.write(getDataBuffer());
+
+      LittleEndian.putShort(shortbuf, 0, getFlags3());
+      bos.write(shortbuf);
+
+      // update total size - length of length-field (4 bytes)
+      byte data[] = bos.toByteArray();
+      totalSize = data.length - LittleEndianConsts.INT_SIZE;
+      LittleEndian.putInt(data, 0, totalSize);
+
+      out.write(data);
+  }
+
+  public void setFlags1(short flags1) {
+      this.flags1 = flags1;
+  }
+
+  public void setFlags2(short flags2) {
+      this.flags2 = flags2;
+  }
+
+  public void setFlags3(short flags3) {
+      this.flags3 = flags3;
+  }
+
+  public void setLabel(String label) {
+      this.label = label;
+  }
+
+  public void setFileName(String fileName) {
+      this.fileName = fileName;
+  }
+
+  public void setCommand(String command) {
+      this.command = command;
+  }
+
+  public void setUnknown1(short unknown1) {
+      this.unknown1 = unknown1;
+  }
+
+  public void setDataBuffer(byte dataBuffer[]) {
+      this.dataBuffer = dataBuffer;
+  }
+}

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java Sun Oct 13 07:39:40 2013
@@ -262,10 +262,7 @@ public final class TestHSSFPicture exten
         System.arraycopy(pictureDataWmf, 22, wmfNoHeader, 0, pictureDataWmf.length-22);
         pictureDataOut = wb.getAllPictures().get(2).getData();
         assertTrue(Arrays.equals(wmfNoHeader, pictureDataOut));
-        
-        FileOutputStream fos = new FileOutputStream("vect.xls");
-        wb.write(fos);
-        fos.close();
+
     }
 
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestOLE2Embeding.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestOLE2Embeding.java?rev=1531623&r1=1531622&r2=1531623&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestOLE2Embeding.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestOLE2Embeding.java Sun Oct 13 07:39:40 2013
@@ -17,11 +17,23 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
 import java.util.List;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.POIDataSamples;
 import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.Ole10Native;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.CreationHelper;
 
 /**
  * 
@@ -39,7 +51,7 @@ public final class TestOLE2Embeding exte
     public void testEmbeddedObjects() throws Exception {
         HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("ole2-embedding.xls");
 
-        List objects = workbook.getAllEmbeddedObjects();
+        List<HSSFObjectData> objects = workbook.getAllEmbeddedObjects();
         assertEquals("Wrong number of objects", 2, objects.size());
         assertEquals("Wrong name for first object", "MBD06CAB431",
                 ((HSSFObjectData)
@@ -48,5 +60,101 @@ public final class TestOLE2Embeding exte
                 ((HSSFObjectData)
                 objects.get(1)).getDirectory().getName());
     }
-}
-
+    
+    public void testReallyEmbedSomething() throws Exception {
+    	HSSFWorkbook wb = new HSSFWorkbook();
+    	HSSFSheet sheet = wb.createSheet();
+    	HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
+
+    	byte[] pictureData = HSSFTestDataSamples.getTestDataFileContent("logoKarmokar4.png");
+    	byte[] picturePPT = POIDataSamples.getSlideShowInstance().readFile("clock.jpg");
+    	int imgIdx = wb.addPicture(pictureData, HSSFWorkbook.PICTURE_TYPE_PNG);
+    	POIFSFileSystem pptPoifs = getSamplePPT();
+    	int pptIdx = wb.addOlePackage(pptPoifs, "Sample-PPT", "sample.ppt", "sample.ppt");
+    	POIFSFileSystem xlsPoifs = getSampleXLS();
+    	int imgPPT = wb.addPicture(picturePPT, HSSFWorkbook.PICTURE_TYPE_JPEG);
+    	int xlsIdx = wb.addOlePackage(xlsPoifs, "Sample-XLS", "sample.xls", "sample.xls");
+    	int txtIdx = wb.addOlePackage(getSampleTXT(), "Sample-TXT", "sample.txt", "sample.txt");
+    	
+        int rowoffset = 5;
+        int coloffset = 5;
+
+        CreationHelper ch = wb.getCreationHelper();
+        HSSFClientAnchor anchor = (HSSFClientAnchor)ch.createClientAnchor();
+        anchor.setAnchor((short)(2+coloffset), 1+rowoffset, 0, 0, (short)(3+coloffset), 5+rowoffset, 0, 0);
+        anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
+    	
+        patriarch.createObjectData(anchor, pptIdx, imgPPT);
+
+        anchor = (HSSFClientAnchor)ch.createClientAnchor();
+        anchor.setAnchor((short)(5+coloffset), 1+rowoffset, 0, 0, (short)(6+coloffset), 5+rowoffset, 0, 0);
+        anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
+        
+        patriarch.createObjectData(anchor, xlsIdx, imgIdx);
+        
+        anchor = (HSSFClientAnchor)ch.createClientAnchor();
+        anchor.setAnchor((short)(3+coloffset), 10+rowoffset, 0, 0, (short)(5+coloffset), 11+rowoffset, 0, 0);
+        anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
+        
+        patriarch.createObjectData(anchor, txtIdx, imgIdx);
+        
+        anchor = (HSSFClientAnchor)ch.createClientAnchor();
+        anchor.setAnchor((short)(1+coloffset), -2+rowoffset, 0, 0, (short)(7+coloffset), 14+rowoffset, 0, 0);
+        anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
+
+        HSSFSimpleShape circle = patriarch.createSimpleShape(anchor);
+        circle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
+        circle.setNoFill(true);
+
+        if (false) {
+	        FileOutputStream fos = new FileOutputStream("embed.xls");
+	        wb.write(fos);
+	        fos.close();
+        }
+        
+        wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
+        
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        HSSFObjectData od = wb.getAllEmbeddedObjects().get(0);
+        Ole10Native ole10 = Ole10Native.createFromEmbeddedOleObject((DirectoryNode)od.getDirectory());
+        bos.reset();
+        pptPoifs.writeFilesystem(bos);
+        assertTrue(Arrays.equals(ole10.getDataBuffer(), bos.toByteArray()));
+
+        od = wb.getAllEmbeddedObjects().get(1);
+        ole10 = Ole10Native.createFromEmbeddedOleObject((DirectoryNode)od.getDirectory());
+        bos.reset();
+        xlsPoifs.writeFilesystem(bos);
+        assertTrue(Arrays.equals(ole10.getDataBuffer(), bos.toByteArray()));
+
+        od = wb.getAllEmbeddedObjects().get(2);
+        ole10 = Ole10Native.createFromEmbeddedOleObject((DirectoryNode)od.getDirectory());
+        assertTrue(Arrays.equals(ole10.getDataBuffer(), getSampleTXT()));
+    
+    }
+    
+    static POIFSFileSystem getSamplePPT() throws IOException {
+    	// scratchpad classes are not available, so we use something pre-cooked
+    	InputStream is = POIDataSamples.getSlideShowInstance().openResourceAsStream("with_textbox.ppt");
+    	POIFSFileSystem poifs = new POIFSFileSystem(is);
+    	is.close();
+        
+        return poifs;
+    }
+    
+    static POIFSFileSystem getSampleXLS() throws IOException {
+        HSSFWorkbook wb = new HSSFWorkbook();
+        HSSFSheet sheet = wb.createSheet();
+        sheet.createRow(5).createCell(2).setCellValue("yo dawg i herd you like embeddet objekts, so we put a ole in your ole so you can save a file while you save a file");
+
+    	ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    	wb.write(bos);
+    	POIFSFileSystem poifs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
+        
+        return poifs;
+    }
+    
+    static byte[] getSampleTXT() {
+        return "All your base are belong to us".getBytes();
+    }    
+}
\ No newline at end of file



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