Bugzilla 55578 - Support embedding OLE1.0 packages in HSSF
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1531623 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
489b0b5bdb
commit
cf7a4c117a
@ -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> */
|
||||
|
@ -64,7 +64,7 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
|
||||
|
||||
|
||||
// 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 EmbeddedObjectRefSubRecord extends SubRecord {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
113
src/java/org/apache/poi/hssf/record/FtCfSubRecord.java
Normal file
113
src/java/org/apache/poi/hssf/record/FtCfSubRecord.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
167
src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java
Normal file
167
src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
@ -193,6 +201,87 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
|
||||
return createPicture((HSSFClientAnchor) anchor, pictureIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -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.EscherBitmapBlip;
|
||||
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.UDFFinder;
|
||||
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 POIDocument implements org.apache.poi.ss
|
||||
|
||||
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 POIDocument implements org.apache.poi.ss
|
||||
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 POIDocument implements org.apache.poi.ss
|
||||
|
||||
}
|
||||
|
||||
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)?
|
||||
*/
|
||||
|
@ -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() )
|
||||
{
|
||||
|
@ -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 "{01}Ole10Native" 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 "{01}Ole10Native" 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;
|
||||
}
|
||||
}
|
||||
|
@ -262,10 +262,7 @@ public final class TestHSSFPicture extends BaseTestPicture {
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 extends TestCase {
|
||||
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 extends TestCase {
|
||||
((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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user