aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Beeker <kiwiwings@apache.org>2017-01-15 02:04:57 +0000
committerAndreas Beeker <kiwiwings@apache.org>2017-01-15 02:04:57 +0000
commit9c2820add6a681f5775601fccb8270b85cd72920 (patch)
treed3131c2107184047d278d6eba14c2fc4fe445ac3
parent4ce3e5def53c893012d6ba709e9beff95a149d48 (diff)
downloadpoi-9c2820add6a681f5775601fccb8270b85cd72920.tar.gz
poi-9c2820add6a681f5775601fccb8270b85cd72920.zip
#60586 - Support embedding OLE1.0 package in XSSF / SS Common
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1778869 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java46
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java11
-rw-r--r--src/java/org/apache/poi/ss/usermodel/Drawing.java13
-rw-r--r--src/java/org/apache/poi/ss/usermodel/Workbook.java15
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFDrawing.java7
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java5
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java130
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java53
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java41
-rw-r--r--src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java125
10 files changed, 409 insertions, 37 deletions
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
index cc6805c5b8..d7baeb58e0 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
@@ -48,6 +48,7 @@ import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.ss.usermodel.Chart;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.Internal;
import org.apache.poi.util.NotImplemented;
@@ -137,6 +138,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
* @param shape to be removed
* @return true of shape is removed
*/
+ @Override
public boolean removeShape(HSSFShape shape) {
boolean isRemoved = _mainSpgrContainer.removeChildRecord(shape.getEscherContainer());
if (isRemoved){
@@ -214,22 +216,13 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
*
* @return newly created shape
*/
+ @Override
public HSSFPicture createPicture(ClientAnchor anchor, int pictureIndex) {
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(POIFSFileSystem,String,String,String)}
- * @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) {
+ @Override
+ public HSSFObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
ObjRecord obj = new ObjRecord();
CommonObjectDataSubRecord ftCmo = new CommonObjectDataSubRecord();
@@ -248,15 +241,15 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
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:
+ case Workbook.PICTURE_TYPE_WMF:
+ case Workbook.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:
+ case Workbook.PICTURE_TYPE_DIB:
+ case Workbook.PICTURE_TYPE_PNG:
+ case Workbook.PICTURE_TYPE_JPEG:
+ case Workbook.PICTURE_TYPE_PICT:
ftCf.setFlags(FtCfSubRecord.BITMAP_BIT);
break;
default:
@@ -280,14 +273,16 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
DirectoryEntry oleRoot;
try {
DirectoryNode dn = _sheet.getWorkbook().getDirectory();
- if (dn == null) throw new FileNotFoundException();
+ 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);
+ HSSFPicture shape = new HSSFPicture(null, (HSSFClientAnchor)anchor);
shape.setPictureIndex(pictureIndex);
EscherContainerRecord spContainer = shape.getEscherContainer();
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
@@ -355,6 +350,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
return shape;
}
+ @Override
public HSSFComment createCellComment(ClientAnchor anchor) {
return createComment((HSSFAnchor) anchor);
}
@@ -362,6 +358,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
/**
* Returns a unmodifiable list of all shapes contained by the patriarch.
*/
+ @Override
public List<HSSFShape> getChildren() {
return Collections.unmodifiableList(_shapes);
}
@@ -369,6 +366,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
/**
* add a shape to this drawing
*/
+ @Override
@Internal
public void addShape(HSSFShape shape) {
shape.setPatriarch(this);
@@ -405,6 +403,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
* Sets the coordinate space of this group. All children are constrained
* to these coordinates.
*/
+ @Override
public void setCoordinates(int x1, int y1, int x2, int y2) {
_spgrRecord.setRectY1(y1);
_spgrRecord.setRectY2(y2);
@@ -415,6 +414,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
/**
* remove all shapes inside patriarch
*/
+ @Override
public void clear() {
ArrayList <HSSFShape> copy = new ArrayList<HSSFShape>(_shapes);
for (HSSFShape shape: copy){
@@ -469,6 +469,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
/**
* @return x coordinate of the left up corner
*/
+ @Override
public int getX1() {
return _spgrRecord.getRectX1();
}
@@ -476,6 +477,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
/**
* @return y coordinate of the left up corner
*/
+ @Override
public int getY1() {
return _spgrRecord.getRectY1();
}
@@ -483,6 +485,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
/**
* @return x coordinate of the right down corner
*/
+ @Override
public int getX2() {
return _spgrRecord.getRectX2();
}
@@ -490,6 +493,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
/**
* @return y coordinate of the right down corner
*/
+ @Override
public int getY2() {
return _spgrRecord.getRectY2();
}
@@ -517,10 +521,12 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
* @param row2 the row (0 based) of the second cell.
* @return the newly created client anchor
*/
+ @Override
public HSSFClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) {
return new HSSFClientAnchor(dx1, dy1, dx2, dy2, (short) col1, row1, (short) col2, row2);
}
+ @Override
@NotImplemented
public Chart createChart(ClientAnchor anchor) {
throw new RuntimeException("NotImplemented");
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index 2f3be03de9..55382236e0 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -2048,6 +2048,16 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
return olemap;
}
+ /**
+ * Adds an OLE package manager object with the given POIFS to the sheet
+ *
+ * @param poiData an POIFS containing the embedded document, to be added
+ * @param label the label of the payload
+ * @param fileName the original filename
+ * @param command the command to open the payload
+ * @return the index of the added ole object
+ * @throws IOException if the object can't be embedded
+ */
public int addOlePackage(POIFSFileSystem poiData, String label, String fileName, String command)
throws IOException {
DirectoryNode root = poiData.getRoot();
@@ -2064,6 +2074,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
return addOlePackage(bos.toByteArray(), label, fileName, command);
}
+ @Override
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
diff --git a/src/java/org/apache/poi/ss/usermodel/Drawing.java b/src/java/org/apache/poi/ss/usermodel/Drawing.java
index e2d55d30a1..13a830ef98 100644
--- a/src/java/org/apache/poi/ss/usermodel/Drawing.java
+++ b/src/java/org/apache/poi/ss/usermodel/Drawing.java
@@ -62,4 +62,17 @@ public interface Drawing<T extends Shape> extends ShapeContainer<T> {
* @return the newly created client anchor
*/
ClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2);
+
+ /**
+ * 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 Workbook#addOlePackage(byte[], String, String, String)}
+ * @param pictureIndex the index of the picture (used as preview image) in the
+ * workbook collection of pictures.
+ *
+ * @return newly created shape
+ */
+ ObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex);
}
diff --git a/src/java/org/apache/poi/ss/usermodel/Workbook.java b/src/java/org/apache/poi/ss/usermodel/Workbook.java
index f5043b727f..5273423de0 100644
--- a/src/java/org/apache/poi/ss/usermodel/Workbook.java
+++ b/src/java/org/apache/poi/ss/usermodel/Workbook.java
@@ -286,6 +286,7 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
* @return the font with the matched attributes or <code>null</code>
* @deprecated POI 3.15 beta 2. Use {@link #findFont(boolean, short, short, String, boolean, boolean, short, byte)} instead.
*/
+ @Deprecated
Font findFont(short boldWeight, short color, short fontHeight, String name, boolean italic, boolean strikeout, short typeOffset, byte underline);
/**
@@ -635,4 +636,18 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
* @since 3.14 beta 2
*/
SpreadsheetVersion getSpreadsheetVersion();
+
+ /**
+ * Adds an OLE package manager object with the given content to the sheet
+ *
+ * @param oleData the payload
+ * @param label the label of the payload
+ * @param fileName the original filename
+ * @param command the command to open the payload
+ *
+ * @return the index of the added ole object, i.e. the storage id
+ *
+ * @throws IOException if the object can't be embedded
+ */
+ int addOlePackage(byte[] oleData, String label, String fileName, String command) throws IOException;
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFDrawing.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFDrawing.java
index 17f1871025..3a645f7676 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFDrawing.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFDrawing.java
@@ -23,6 +23,7 @@ import org.apache.poi.ss.usermodel.Chart;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.ObjectData;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFShape;
@@ -63,8 +64,14 @@ public class SXSSFDrawing implements Drawing<XSSFShape> {
}
@Override
+ public ObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
+ return _drawing.createObjectData(anchor, storageId, pictureIndex);
+ }
+
+ @Override
public Iterator<XSSFShape> iterator() {
return _drawing.getShapes().iterator();
}
+
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
index a11bef3100..611f16bc0c 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
@@ -1391,5 +1391,10 @@ public class SXSSFWorkbook implements Workbook {
return SpreadsheetVersion.EXCEL2007;
}
+ @Override
+ public int addOlePackage(byte[] oleData, String label, String fileName, String command) throws IOException {
+ return _wb.addOlePackage(oleData, label, fileName, command);
+ }
+
//end of interface implementation
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
index 5c7395ed3e..35f71381c3 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
@@ -28,9 +28,16 @@ import java.util.List;
import javax.xml.namespace.QName;
+import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.POIXMLException;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;
+import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.util.CellAddress;
@@ -45,7 +52,9 @@ import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
@@ -59,19 +68,22 @@ import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTPicture;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.STEditAs;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObject;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObjects;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
/**
* Represents a SpreadsheetML drawing
*/
public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSSFShape> {
private static final POILogger LOG = POILogFactory.getLogger(XSSFDrawing.class);
-
+
/**
* Root element of the SpreadsheetML Drawing part
*/
private CTDrawing drawing;
private long numOfGraphicFrames = 0L;
-
+
protected static final String NAMESPACE_A = XSSFRelation.NS_DRAWINGML;
protected static final String NAMESPACE_C = XSSFRelation.NS_CHART;
@@ -90,7 +102,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
*
* @param part the package part holding the drawing data,
* the content type must be <code>application/vnd.openxmlformats-officedocument.drawing+xml</code>
- *
+ *
* @since POI 3.14-Beta1
*/
public XSSFDrawing(PackagePart part) throws IOException, XmlException {
@@ -105,7 +117,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
is.close();
}
}
-
+
/**
* Construct a new CTDrawing bean. By default, it's just an empty placeholder for drawing objects
*
@@ -194,7 +206,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
shape.anchor = anchor;
shape.setPictureReference(rel);
ctShape.getSpPr().setXfrm(createXfrm(anchor));
-
+
return shape;
}
@@ -319,7 +331,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
@Override
public XSSFComment createCellComment(ClientAnchor anchor) {
XSSFClientAnchor ca = (XSSFClientAnchor)anchor;
- XSSFSheet sheet = (XSSFSheet)getParent();
+ XSSFSheet sheet = getSheet();
//create comments and vmlDrawing parts if they don't exist
CommentsTable comments = sheet.getCommentsTable(true);
@@ -344,7 +356,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
if(comments.findCellComment(ref) != null) {
throw new IllegalArgumentException("Multiple cell comments in one cell are not allowed, cell: " + ref);
}
-
+
return new XSSFComment(comments, comments.newComment(ref), vmlShape);
}
@@ -368,7 +380,85 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
graphicFrame.setName("Diagramm" + frameId);
return graphicFrame;
}
-
+
+ @Override
+ public XSSFObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
+ XSSFSheet sh = getSheet();
+ PackagePart sheetPart = sh.getPackagePart();
+ long shapeId = newShapeId();
+
+ // add reference to OLE part
+ PackagePartName olePN;
+ try {
+ olePN = PackagingURIHelper.createPartName( "/xl/embeddings/oleObject"+storageId+".bin" );
+ } catch (InvalidFormatException e) {
+ throw new POIXMLException(e);
+ }
+ PackageRelationship olePR = sheetPart.addRelationship( olePN, TargetMode.INTERNAL, POIXMLDocument.OLE_OBJECT_REL_TYPE );
+
+ // add reference to image part
+ XSSFPictureData imgPD = sh.getWorkbook().getAllPictures().get(pictureIndex);
+ PackagePartName imgPN = imgPD.getPackagePart().getPartName();
+ PackageRelationship imgSheetPR = sheetPart.addRelationship( imgPN, TargetMode.INTERNAL, PackageRelationshipTypes.IMAGE_PART );
+ PackageRelationship imgDrawPR = getPackagePart().addRelationship( imgPN, TargetMode.INTERNAL, PackageRelationshipTypes.IMAGE_PART );
+
+
+ // add OLE part metadata to sheet
+ CTWorksheet cwb = sh.getCTWorksheet();
+ CTOleObjects oo = cwb.isSetOleObjects() ? cwb.getOleObjects() : cwb.addNewOleObjects();
+
+ CTOleObject ole1 = oo.addNewOleObject();
+ ole1.setProgId("Package");
+ ole1.setShapeId(shapeId);
+ ole1.setId(olePR.getId());
+
+ XmlCursor cur1 = ole1.newCursor();
+ cur1.toEndToken();
+ cur1.beginElement("objectPr", XSSFRelation.NS_SPREADSHEETML);
+ cur1.insertAttributeWithValue("id", PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS, imgSheetPR.getId());
+ cur1.insertAttributeWithValue("defaultSize", "0");
+ cur1.beginElement("anchor", XSSFRelation.NS_SPREADSHEETML);
+ cur1.insertAttributeWithValue("moveWithCells", "1");
+
+ CTTwoCellAnchor ctAnchor = createTwoCellAnchor((XSSFClientAnchor)anchor);
+
+ XmlCursor cur2 = ctAnchor.newCursor();
+ cur2.copyXmlContents(cur1);
+ cur2.dispose();
+
+ cur1.toParent();
+ cur1.toFirstChild();
+ cur1.setName(new QName(XSSFRelation.NS_SPREADSHEETML, "from"));
+ cur1.toNextSibling();
+ cur1.setName(new QName(XSSFRelation.NS_SPREADSHEETML, "to"));
+
+ cur1.dispose();
+
+ // add a new shape and link OLE & image part
+ CTShape ctShape = ctAnchor.addNewSp();
+ ctShape.set(XSSFObjectData.prototype());
+ ctShape.getSpPr().setXfrm(createXfrm((XSSFClientAnchor)anchor));
+
+ // workaround for not having the vmlDrawing filled
+ CTBlipFillProperties blipFill = ctShape.getSpPr().addNewBlipFill();
+ blipFill.addNewBlip().setEmbed(imgDrawPR.getId());
+ blipFill.addNewStretch().addNewFillRect();
+
+ CTNonVisualDrawingProps cNvPr = ctShape.getNvSpPr().getCNvPr();
+ cNvPr.setId(shapeId);
+
+ XmlCursor extCur = cNvPr.getExtLst().getExtArray(0).newCursor();
+ extCur.toFirstChild();
+ extCur.setAttributeText(new QName("spid"), "_x0000_s"+shapeId);
+ extCur.dispose();
+
+ XSSFObjectData shape = new XSSFObjectData(this, ctShape);
+ shape.anchor = (XSSFClientAnchor)anchor;
+
+ return shape;
+ }
+
+
/**
* Returns all charts in this drawing.
*/
@@ -410,7 +500,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
CTPoint2D off = xfrm.addNewOff();
off.setX(anchor.getDx1());
off.setY(anchor.getDy1());
- XSSFSheet sheet = (XSSFSheet)getParent();
+ XSSFSheet sheet = getSheet();
double widthPx = 0;
for (int col=anchor.getCol1(); col<anchor.getCol2(); col++) {
widthPx += sheet.getColumnWidthInPixels(col);
@@ -424,11 +514,11 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
CTPositiveSize2D ext = xfrm.addNewExt();
ext.setCx(width - anchor.getDx1() + anchor.getDx2());
ext.setCy(height - anchor.getDy1() + anchor.getDy2());
-
+
// TODO: handle vflip/hflip
return xfrm;
}
-
+
private long newShapeId(){
return drawing.sizeOfTwoCellAnchorArray() + 1;
}
@@ -462,7 +552,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
}
return lst;
}
-
+
private void addShapes(XmlCursor cur, List<XSSFShape> lst) {
try {
do {
@@ -470,7 +560,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
if (cur.toFirstChild()) {
do {
XmlObject obj = cur.getObject();
-
+
XSSFShape shape;
if (obj instanceof CTMarker) {
// ignore anchor elements
@@ -480,7 +570,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
} else if(obj instanceof CTConnector) {
shape = new XSSFConnector(this, (CTConnector)obj) ;
} else if(obj instanceof CTShape) {
- shape = hasOleLink(obj)
+ shape = hasOleLink(obj)
? new XSSFObjectData(this, (CTShape)obj)
: new XSSFSimpleShape(this, (CTShape)obj) ;
} else if(obj instanceof CTGraphicalObjectFrame) {
@@ -492,7 +582,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
+ "this unlinks the returned Shapes from the underlying xml content, "
+ "so those shapes can't be used to modify the drawing, "
+ "i.e. modifications will be ignored!");
-
+
// XmlAnyTypeImpl is returned for AlternateContent parts, which might contain a CTDrawing
cur.push();
cur.toFirstChild();
@@ -522,7 +612,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
assert(shape != null);
shape.anchor = getAnchorFromParent(obj);
lst.add(shape);
-
+
} while (cur.toNextSibling());
}
cur.pop();
@@ -575,4 +665,12 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
public Iterator<XSSFShape> iterator() {
return getShapes().iterator();
}
+
+ /**
+ * @return the sheet associated with the drawing
+ */
+ public XSSFSheet getSheet() {
+ return (XSSFSheet)getParent();
+ }
+
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java
index ab51df81ee..2221979411 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFObjectData.java
@@ -36,7 +36,17 @@ import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.xmlbeans.XmlCursor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeArtExtension;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeArtExtensionList;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObject;
/**
@@ -59,13 +69,54 @@ public class XSSFObjectData extends XSSFSimpleShape implements ObjectData {
/**
* Prototype with the default structure of a new auto-shape.
*/
+ /**
+ * Prototype with the default structure of a new auto-shape.
+ */
protected static CTShape prototype() {
+ final String drawNS = "http://schemas.microsoft.com/office/drawing/2010/main";
+
if(prototype == null) {
- prototype = XSSFSimpleShape.prototype();
+ CTShape shape = CTShape.Factory.newInstance();
+
+ CTShapeNonVisual nv = shape.addNewNvSpPr();
+ CTNonVisualDrawingProps nvp = nv.addNewCNvPr();
+ nvp.setId(1);
+ nvp.setName("Shape 1");
+// nvp.setHidden(true);
+ CTOfficeArtExtensionList extLst = nvp.addNewExtLst();
+ // https://msdn.microsoft.com/en-us/library/dd911027(v=office.12).aspx
+ CTOfficeArtExtension ext = extLst.addNewExt();
+ ext.setUri("{63B3BB69-23CF-44E3-9099-C40C66FF867C}");
+ XmlCursor cur = ext.newCursor();
+ cur.toEndToken();
+ cur.beginElement(new QName(drawNS, "compatExt", "a14"));
+ cur.insertNamespace("a14", drawNS);
+ cur.insertAttributeWithValue("spid", "_x0000_s1");
+ cur.dispose();
+
+ nv.addNewCNvSpPr();
+
+ CTShapeProperties sp = shape.addNewSpPr();
+ CTTransform2D t2d = sp.addNewXfrm();
+ CTPositiveSize2D p1 = t2d.addNewExt();
+ p1.setCx(0);
+ p1.setCy(0);
+ CTPoint2D p2 = t2d.addNewOff();
+ p2.setX(0);
+ p2.setY(0);
+
+ CTPresetGeometry2D geom = sp.addNewPrstGeom();
+ geom.setPrst(STShapeType.RECT);
+ geom.addNewAvLst();
+
+ prototype = shape;
}
return prototype;
}
+
+
+
@Override
public String getOLE2ClassName() {
return getOleObject().getProgId();
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
index c6df00599d..6aa2064c38 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
@@ -47,6 +47,7 @@ import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.poi.POIXMLProperties;
+import org.apache.poi.hpsf.ClassID;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -58,6 +59,9 @@ import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.poifs.crypt.HashAlgorithm;
+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.SpreadsheetVersion;
import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
@@ -2437,4 +2441,41 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
}
return null;
}
+
+ @Override
+ public int addOlePackage(byte[] oleData, String label, String fileName, String command)
+ throws IOException {
+ // find an unused part name
+ OPCPackage opc = getPackage();
+ PackagePartName pnOLE;
+ int oleId=0;
+ do {
+ try {
+ pnOLE = PackagingURIHelper.createPartName( "/xl/embeddings/oleObject"+(++oleId)+".bin" );
+ } catch (InvalidFormatException e) {
+ throw new IOException("ole object name not recognized", e);
+ }
+ } while (opc.containPart(pnOLE));
+
+ PackagePart pp = opc.createPart( pnOLE, "application/vnd.openxmlformats-officedocument.oleObject" );
+
+ Ole10Native ole10 = new Ole10Native(label, fileName, command, oleData);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(oleData.length+500);
+ ole10.writeOut(bos);
+
+ POIFSFileSystem poifs = new POIFSFileSystem();
+ DirectoryNode root = poifs.getRoot();
+ root.createDocument(Ole10Native.OLE10_NATIVE, new ByteArrayInputStream(bos.toByteArray()));
+ root.setStorageClsid(ClassID.OLE10_PACKAGE);
+
+ // TODO: generate CombObj stream
+
+ OutputStream os = pp.getOutputStream();
+ poifs.writeFilesystem(os);
+ os.close();
+ poifs.close();
+
+ return oleId;
+ }
}
diff --git a/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java b/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java
new file mode 100644
index 0000000000..0664d64b10
--- /dev/null
+++ b/src/ooxml/testcases/org/apache/poi/ss/usermodel/TestEmbedOLEPackage.java
@@ -0,0 +1,125 @@
+/* ====================================================================
+ 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.ss.usermodel;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.imageio.ImageIO;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.sl.usermodel.AutoShape;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.ss.extractor.EmbeddedData;
+import org.apache.poi.ss.extractor.EmbeddedExtractor;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+public class TestEmbedOLEPackage {
+ @Test
+ public void embedXSSF() throws IOException {
+ Workbook wb1 = new XSSFWorkbook();
+ Sheet sh = wb1.createSheet();
+ int picIdx = wb1.addPicture(getSamplePng(), Workbook.PICTURE_TYPE_PNG);
+ byte samplePPTX[] = getSamplePPT(true);
+ int oleIdx = wb1.addOlePackage(samplePPTX, "dummy.pptx", "dummy.pptx", "dummy.pptx");
+
+ Drawing<?> pat = sh.createDrawingPatriarch();
+ ClientAnchor anchor = pat.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
+ pat.createObjectData(anchor, oleIdx, picIdx);
+
+ Workbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(wb1);
+
+ pat = wb2.getSheetAt(0).getDrawingPatriarch();
+ assertTrue(pat.iterator().next() instanceof ObjectData);
+
+ EmbeddedExtractor ee = new EmbeddedExtractor();
+ EmbeddedData ed = ee.extractAll(wb2.getSheetAt(0)).get(0);
+ assertArrayEquals(samplePPTX, ed.getEmbeddedData());
+
+ wb2.close();
+ wb1.close();
+ }
+
+ @Test
+ public void embedHSSF() throws IOException {
+ try {
+ Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
+ } catch (Exception e) {
+ assumeTrue(false);
+ }
+
+ Workbook wb1 = new HSSFWorkbook();
+ Sheet sh = wb1.createSheet();
+ int picIdx = wb1.addPicture(getSamplePng(), Workbook.PICTURE_TYPE_PNG);
+ byte samplePPT[] = getSamplePPT(false);
+ int oleIdx = wb1.addOlePackage(samplePPT, "dummy.ppt", "dummy.ppt", "dummy.ppt");
+
+ Drawing<?> pat = sh.createDrawingPatriarch();
+ ClientAnchor anchor = pat.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
+ pat.createObjectData(anchor, oleIdx, picIdx);
+
+ Workbook wb2 = HSSFTestDataSamples.writeOutAndReadBack((HSSFWorkbook)wb1);
+
+ pat = wb2.getSheetAt(0).getDrawingPatriarch();
+ assertTrue(pat.iterator().next() instanceof ObjectData);
+
+ EmbeddedExtractor ee = new EmbeddedExtractor();
+ EmbeddedData ed = ee.extractAll(wb2.getSheetAt(0)).get(0);
+ assertArrayEquals(samplePPT, ed.getEmbeddedData());
+
+ wb2.close();
+ wb1.close();
+ }
+
+ static byte[] getSamplePng() throws IOException {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ URL imgUrl = cl.getResource("javax/swing/plaf/metal/icons/ocean/directory.gif");
+ BufferedImage img = ImageIO.read(imgUrl);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ImageIO.write(img, "PNG", bos);
+ return bos.toByteArray();
+ }
+
+ static byte[] getSamplePPT(boolean ooxml) throws IOException {
+ SlideShow<?,?> ppt = (ooxml) ? new XMLSlideShow() : new org.apache.poi.hslf.usermodel.HSLFSlideShow();
+ Slide<?,?> slide = ppt.createSlide();
+
+ AutoShape<?,?> sh1 = slide.createAutoShape();
+ sh1.setShapeType(ShapeType.STAR_32);
+ sh1.setAnchor(new java.awt.Rectangle(50, 50, 100, 200));
+ sh1.setFillColor(java.awt.Color.red);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ppt.write(bos);
+ ppt.close();
+
+ return bos.toByteArray();
+ }
+}