aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java14
-rw-r--r--src/java/org/apache/poi/sl/usermodel/ObjectData.java102
-rw-r--r--src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java96
-rw-r--r--src/java/org/apache/poi/sl/usermodel/ObjectShape.java152
-rw-r--r--src/java/org/apache/poi/sl/usermodel/ShapeContainer.java7
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java24
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java18
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java25
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java93
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java323
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java8
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java37
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java37
-rw-r--r--src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java220
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java10
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java81
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java13
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java44
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java (renamed from src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java)141
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java3
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java5
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java11
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java12
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java19
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java2
25 files changed, 1355 insertions, 142 deletions
diff --git a/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java b/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
index 3cc995d153..97b9cd3d18 100644
--- a/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
+++ b/src/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
@@ -21,8 +21,8 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
-import org.apache.poi.hslf.model.OLEShape;
import org.apache.poi.hslf.usermodel.HSLFObjectData;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFPictureShape;
import org.apache.poi.hslf.usermodel.HSLFShape;
@@ -67,19 +67,19 @@ public final class DataExtraction {
for (HSLFSlide slide : ppt.getSlides()) {
//extract embedded OLE documents
for (HSLFShape shape : slide.getShapes()) {
- if (shape instanceof OLEShape) {
+ if (shape instanceof HSLFObjectShape) {
oleIdx++;
- OLEShape ole = (OLEShape) shape;
+ HSLFObjectShape ole = (HSLFObjectShape) shape;
HSLFObjectData data = ole.getObjectData();
String name = ole.getInstanceName();
if ("Worksheet".equals(name)) {
//read xls
@SuppressWarnings({ "unused", "resource" })
- HSSFWorkbook wb = new HSSFWorkbook(data.getData());
+ HSSFWorkbook wb = new HSSFWorkbook(data.getInputStream());
} else if ("Document".equals(name)) {
- HWPFDocument doc = new HWPFDocument(data.getData());
+ HWPFDocument doc = new HWPFDocument(data.getInputStream());
//read the word document
Range r = doc.getRange();
for(int k = 0; k < r.numParagraphs(); k++) {
@@ -93,8 +93,8 @@ public final class DataExtraction {
out.close();
doc.close();
} else {
- FileOutputStream out = new FileOutputStream(ole.getProgID() + "-"+(oleIdx+1)+".dat");
- InputStream dis = data.getData();
+ FileOutputStream out = new FileOutputStream(ole.getProgId() + "-"+(oleIdx+1)+".dat");
+ InputStream dis = data.getInputStream();
byte[] chunk = new byte[2048];
int count;
while ((count = dis.read(chunk)) >= 0) {
diff --git a/src/java/org/apache/poi/sl/usermodel/ObjectData.java b/src/java/org/apache/poi/sl/usermodel/ObjectData.java
new file mode 100644
index 0000000000..db30a9b245
--- /dev/null
+++ b/src/java/org/apache/poi/sl/usermodel/ObjectData.java
@@ -0,0 +1,102 @@
+/* ====================================================================
+ 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.sl.usermodel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Common interface for OLE shapes, i.e. shapes linked to embedded documents
+ *
+ * @since POI 4.0.0
+ */
+public interface ObjectData {
+
+ /**
+ * Gets an input stream which returns the binary of the embedded data.
+ *
+ * @return the input stream which will contain the binary of the embedded data.
+ */
+ InputStream getInputStream() throws IOException;
+
+
+ /**
+ * @return the object data as stream (for writing)
+ */
+ OutputStream getOutputStream() throws IOException;
+
+ /**
+ * Convenience method to get the embedded data as byte array.
+ *
+ * @return the embedded data.
+ */
+ default byte[] getBytes() throws IOException {
+ try (InputStream is = getInputStream()) {
+ return IOUtils.toByteArray(is);
+ }
+ }
+
+ /**
+ * @return does this ObjectData have an associated POIFS Directory Entry?
+ * (Not all do, those that don't have a data portion)
+ */
+ default boolean hasDirectoryEntry() {
+ try (final InputStream is = FileMagic.prepareToCheckMagic(getInputStream())) {
+ FileMagic fm = FileMagic.valueOf(is);
+ return fm == FileMagic.OLE2;
+ } catch (IOException e) {
+ POILogger LOG = POILogFactory.getLogger(ObjectData.class);
+ LOG.log(POILogger.WARN, "Can't determine filemagic of ole stream", e);
+ return false;
+ }
+ }
+
+ /**
+ * Gets the object data. Only call for ones that have
+ * data though. See {@link #hasDirectoryEntry()}.
+ * The caller has to close the corresponding POIFSFileSystem
+ *
+ * @return the object data as an OLE2 directory.
+ * @throws IOException if there was an error reading the data.
+ */
+ @SuppressWarnings("resource")
+ default DirectoryEntry getDirectory() throws IOException {
+ try (final InputStream is = getInputStream()) {
+ return new POIFSFileSystem(is).getRoot();
+ }
+ }
+
+ /**
+ * @return the OLE2 Class Name of the object
+ */
+ String getOLE2ClassName();
+
+ /**
+ * @return a filename suggestion - inspecting/interpreting the Directory object probably gives a better result
+ */
+ String getFileName();
+
+}
diff --git a/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java b/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java
new file mode 100644
index 0000000000..1851b0c8b0
--- /dev/null
+++ b/src/java/org/apache/poi/sl/usermodel/ObjectMetaData.java
@@ -0,0 +1,96 @@
+/* ====================================================================
+ 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.sl.usermodel;
+
+import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.hpsf.ClassIDPredefined;
+import org.apache.poi.util.Beta;
+
+@Beta
+public interface ObjectMetaData {
+ enum Application {
+ EXCEL_V8("Worksheet", "Excel.Sheet.8", "Package", ClassIDPredefined.EXCEL_V8),
+ EXCEL_V12("Worksheet", "Excel.Sheet.12", "Package", ClassIDPredefined.EXCEL_V12),
+ WORD_V8("Document", "Word.Document.8", "Package", ClassIDPredefined.WORD_V8),
+ WORD_V12("Document", "Word.Document.12", "Package", ClassIDPredefined.WORD_V12),
+ PDF("PDF", "AcroExch.Document", "Contents", ClassIDPredefined.PDF),
+ CUSTOM(null, null, null, null);
+
+ String objectName;
+ String progId;
+ String oleEntry;
+ ClassID classId;
+
+ Application(String objectName, String progId, String oleEntry, ClassIDPredefined classId) {
+ this.objectName = objectName;
+ this.progId = progId;
+ this.classId = (classId == null) ? null : classId.getClassID();
+ this.oleEntry = oleEntry;
+ }
+
+ public static Application lookup(String progId) {
+ for (Application a : values()) {
+ if (a.progId != null && a.progId.equals(progId)) {
+ return a;
+ }
+ }
+ return null;
+ }
+
+
+ public ObjectMetaData getMetaData() {
+ return new ObjectMetaData() {
+ public String getObjectName() {
+ return objectName;
+ }
+
+ public String getProgId() {
+ return progId;
+ }
+
+ public String getOleEntry() {
+ return oleEntry;
+ }
+
+ public ClassID getClassID() {
+ return classId;
+ }
+ };
+ }
+ }
+
+ /**
+ * @return the name of the OLE shape
+ */
+ String getObjectName();
+
+ /**
+ * @return the program id assigned to the OLE container application
+ */
+ String getProgId();
+
+ /**
+ * @return the storage classid of the OLE entry
+ */
+ ClassID getClassID();
+
+ /**
+ * @return the name of the OLE entry inside the oleObject#.bin
+ */
+ String getOleEntry();
+}
diff --git a/src/java/org/apache/poi/sl/usermodel/ObjectShape.java b/src/java/org/apache/poi/sl/usermodel/ObjectShape.java
new file mode 100644
index 0000000000..c7d421950e
--- /dev/null
+++ b/src/java/org/apache/poi/sl/usermodel/ObjectShape.java
@@ -0,0 +1,152 @@
+/* ====================================================================
+ 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.sl.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectMetaData.Application;
+import org.apache.poi.util.IOUtils;
+
+/**
+ * An shape which references an embedded OLE object
+ *
+ * @since POI 4.0.0
+ */
+public interface ObjectShape<
+ S extends Shape<S,P>,
+ P extends TextParagraph<S,P,? extends TextRun>
+> extends Shape<S,P>, PlaceableShape<S,P> {
+
+ /**
+ * Returns the picture data for this picture.
+ *
+ * @return the picture data for this picture.
+ */
+ PictureData getPictureData();
+
+ /**
+ * Returns the ProgID that stores the OLE Programmatic Identifier.
+ * A ProgID is a string that uniquely identifies a given object, for example,
+ * "Word.Document.8" or "Excel.Sheet.8".
+ *
+ * @return the ProgID
+ */
+ String getProgId();
+
+ /**
+ * Returns the full name of the embedded object,
+ * e.g. "Microsoft Word Document" or "Microsoft Office Excel Worksheet".
+ *
+ * @return the full name of the embedded object
+ */
+ String getFullName();
+
+ /**
+ * Updates the ole data. If there wasn't an object registered before, a new
+ * ole embedding is registered in the parent slideshow.<p>
+ *
+ * For HSLF this needs to be a {@link POIFSFileSystem} stream.
+ *
+ * @param application a preset application enum
+ * @param metaData or a custom metaData object, can be {@code null} if the application has been set
+ *
+ * @return an {@link OutputStream} which receives the new data, the data will be persisted on {@code close()}
+ *
+ * @throws IOException if the linked object data couldn't be found or a new object data couldn't be initialized
+ */
+ OutputStream updateObjectData(ObjectMetaData.Application application, ObjectMetaData metaData) throws IOException;
+
+ /**
+ * Reads the ole data as stream - the application specific stream is served
+ * The {@link #readObjectDataRaw() raw data} serves the outer/wrapped object, which is usually a
+ * {@link POIFSFileSystem} stream, whereas this method return the unwrapped entry
+ *
+ * @return an {@link InputStream} which serves the object data
+ *
+ * @throws IOException if the linked object data couldn't be found
+ */
+ default InputStream readObjectData() throws IOException {
+ final String progId = getProgId();
+ if (progId == null) {
+ throw new IllegalStateException(
+ "Ole object hasn't been initialized or provided in the source xml. " +
+ "use updateObjectData() first or check the corresponding slideXXX.xml");
+ }
+
+ final Application app = Application.lookup(progId);
+
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
+ try (final InputStream is = FileMagic.prepareToCheckMagic(readObjectDataRaw())) {
+ final FileMagic fm = FileMagic.valueOf(is);
+ if (fm == FileMagic.OLE2) {
+ try (final POIFSFileSystem poifs = new POIFSFileSystem(is)) {
+ String[] names = {
+ (app == null) ? null : app.getMetaData().getOleEntry(),
+ // fallback to the usual suspects
+ "Package",
+ "Contents",
+ "CONTENTS",
+ "CONTENTSV30",
+ };
+ final DirectoryNode root = poifs.getRoot();
+ String entryName = null;
+ for (String n : names) {
+ if (root.hasEntry(n)) {
+ entryName = n;
+ break;
+ }
+ }
+ if (entryName == null) {
+ poifs.writeFilesystem(bos);
+ } else {
+ try (final InputStream is2 = poifs.createDocumentInputStream(entryName)) {
+ IOUtils.copy(is2, bos);
+ }
+ }
+ }
+ } else {
+ IOUtils.copy(is, bos);
+ }
+ }
+
+ return new ByteArrayInputStream(bos.toByteArray());
+ }
+
+ /**
+ * Convenience method to return the raw data as {@code InputStream}
+ *
+ * @return the raw data stream
+ *
+ * @throws IOException if the data couldn't be retrieved
+ */
+ default InputStream readObjectDataRaw() throws IOException {
+ return getObjectData().getInputStream();
+ }
+
+ /**
+ * @return the data object
+ */
+ ObjectData getObjectData();
+}
diff --git a/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java b/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java
index ba02e4b05e..7706828c52 100644
--- a/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java
+++ b/src/java/org/apache/poi/sl/usermodel/ShapeContainer.java
@@ -84,4 +84,11 @@ public interface ShapeContainer<
* @param numCols the number of columns
*/
TableShape<S,P> createTable(int numRows, int numCols);
+
+ /**
+ * Create a new OLE object shape with the given pictureData as preview image
+ *
+ * @param pictureData the preview image
+ */
+ ObjectShape<?,?> createOleShape(PictureData pictureData);
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java
index 058507c01e..42e375ae09 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java
@@ -18,20 +18,30 @@ package org.apache.poi.xslf.usermodel;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import org.apache.poi.POIXMLDocumentPart.RelationPart;
+import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+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.PackagingURIHelper;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
-/**
- * @author Yegor Kozlov
- */
@Beta
public class XSLFDrawing {
private XSLFSheet _sheet;
@@ -110,4 +120,12 @@ public class XSLFDrawing {
shape.setAnchor(new Rectangle2D.Double());
return shape;
}
+
+ public XSLFObjectShape createOleShape(String pictureRel) {
+ CTGraphicalObjectFrame obj = _spTree.addNewGraphicFrame();
+ obj.set(XSLFObjectShape.prototype(_shapeId++, pictureRel));
+ XSLFObjectShape shape = new XSLFObjectShape(obj, _sheet);
+ shape.setAnchor(new Rectangle2D.Double());
+ return shape;
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
index f08e1d1de4..b2cf29e43b 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
@@ -37,6 +37,7 @@ import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
@@ -86,13 +87,24 @@ public class XSLFGraphicFrame extends XSLFShape implements GraphicalFrame<XSLFSh
static XSLFGraphicFrame create(CTGraphicalObjectFrame shape, XSLFSheet sheet){
- String uri = shape.getGraphic().getGraphicData().getUri();
- if(XSLFTable.TABLE_URI.equals(uri)){
+ switch (getUri(shape)) {
+ case XSLFTable.TABLE_URI:
return new XSLFTable(shape, sheet);
- } else {
+ case XSLFObjectShape.OLE_URI:
+ return new XSLFObjectShape(shape, sheet);
+ default:
return new XSLFGraphicFrame(shape, sheet);
}
}
+
+ private static String getUri(CTGraphicalObjectFrame shape) {
+ final CTGraphicalObject g = shape.getGraphic();
+ if (g == null) {
+ return null;
+ }
+ CTGraphicalObjectData gd = g.getGraphicData();
+ return (gd == null) ? null : gd.getUri();
+ }
/**
* Rotate this shape.
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
index b2fc838547..e6425d0bc0 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
@@ -19,6 +19,7 @@
package org.apache.poi.xslf.usermodel;
+import java.awt.Dimension;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
@@ -44,6 +45,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
@@ -275,6 +277,29 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
return sh;
}
+ @Override
+ public XSLFObjectShape createOleShape(PictureData pictureData) {
+ if (!(pictureData instanceof XSLFPictureData)) {
+ throw new IllegalArgumentException("pictureData needs to be of type XSLFPictureData");
+ }
+ XSLFPictureData xPictureData = (XSLFPictureData)pictureData;
+ PackagePart pic = xPictureData.getPackagePart();
+
+ PackageRelationship rel = getSheet().getPackagePart().addRelationship(
+ pic.getPartName(), TargetMode.INTERNAL, XSLFRelation.IMAGES.getRelation());
+
+ XSLFObjectShape sh = getDrawing().createOleShape(rel.getId());
+ CTOleObject oleObj = sh.getCTOleObject();
+ Dimension dim = pictureData.getImageDimension();
+ oleObj.setImgW(Units.toEMU(dim.getWidth()));
+ oleObj.setImgH(Units.toEMU(dim.getHeight()));
+
+
+ getShapes().add(sh);
+ sh.setParent(this);
+ return sh;
+ }
+
public XSLFTable createTable(){
XSLFTable sh = getDrawing().createTable();
_shapes.add(sh);
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java
new file mode 100644
index 0000000000..1532dae83f
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectData.java
@@ -0,0 +1,93 @@
+/*
+ * ====================================================================
+ * 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.xslf.usermodel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.sl.usermodel.ObjectData;
+import org.apache.poi.util.Beta;
+
+/**
+ * An XSLFOleData instance holds the ole binary stream/object
+ */
+@Beta
+public final class XSLFObjectData extends POIXMLDocumentPart implements ObjectData {
+
+ /**
+ * Create a new XSLFOleData node
+ */
+ protected XSLFObjectData() {
+ super();
+ }
+
+ /**
+ * Construct XSLFOleData from a package part
+ *
+ * @param part the package part holding the ole data
+ *
+ * @since POI 3.14-Beta1
+ */
+ public XSLFObjectData(final PackagePart part) {
+ super(part);
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return getPackagePart().getInputStream();
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ final PackagePart pp = getPackagePart();
+ pp.clear();
+ return pp.getOutputStream();
+ }
+
+ /**
+ * *PictureData objects store the actual content in the part directly without keeping a
+ * copy like all others therefore we need to handle them differently.
+ */
+ @Override
+ protected void prepareForCommit() {
+ // do not clear the part here
+ }
+
+
+ public void setData(final byte[] data) throws IOException {
+ try (final OutputStream os = getPackagePart().getOutputStream()) {
+ os.write(data);
+ }
+ }
+
+ @Override
+ public String getOLE2ClassName() {
+ return null;
+ }
+
+ @Override
+ public String getFileName() {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java
new file mode 100644
index 0000000000..ffa6b9eb19
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java
@@ -0,0 +1,323 @@
+/*
+ * ====================================================================
+ * 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.xslf.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.xml.namespace.QName;
+
+import org.apache.poi.POIXMLDocumentPart.RelationPart;
+import org.apache.poi.POIXMLException;
+import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.Ole10Native;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectMetaData;
+import org.apache.poi.sl.usermodel.ObjectMetaData.Application;
+import org.apache.poi.sl.usermodel.ObjectShape;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.Internal;
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
+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.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrameNonVisual;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual;
+
+public class XSLFObjectShape extends XSLFGraphicFrame implements ObjectShape<XSLFShape,XSLFTextParagraph> {
+
+ /* package */ static final String OLE_URI = "http://schemas.openxmlformats.org/presentationml/2006/ole";
+
+ private CTOleObject _oleObject;
+ private XSLFPictureData _data;
+
+ /*package*/ XSLFObjectShape(CTGraphicalObjectFrame shape, XSLFSheet sheet){
+ super(shape, sheet);
+
+ CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
+ XmlCursor xc = god.newCursor();
+ // select oleObj potentially under AlternateContent
+ // usually the mc:Choice element will be selected first
+ xc.selectPath("declare namespace p='"+PML_NS+"' .//p:oleObj");
+ try {
+ if (!xc.toNextSelection()) {
+ throw new IllegalStateException("p:oleObj element was not found in\n " + god);
+ }
+
+ XmlObject xo = xc.getObject();
+ // Pesky XmlBeans bug - see Bugzilla #49934
+ // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
+ if (xo instanceof XmlAnyTypeImpl){
+ String errStr =
+ "Schemas (*.xsb) for CTOleObject can't be loaded - usually this happens when OSGI " +
+ "loading is used and the thread context classloader has no reference to " +
+ "the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
+ "e.g. with CTOleObject.class.getClassLoader()"
+ ;
+ throw new IllegalStateException(errStr);
+ }
+ _oleObject = (CTOleObject)xo;
+ } finally {
+ xc.dispose();
+ }
+ }
+
+ @Internal
+ public CTOleObject getCTOleObject(){
+ return _oleObject;
+ }
+
+ @Override
+ public XSLFObjectData getObjectData() {
+ String oleRel = getCTOleObject().getId();
+ return getSheet().getRelationPartById(oleRel).getDocumentPart();
+ }
+
+ @Override
+ public String getProgId() {
+ return (_oleObject == null) ? null : _oleObject.getProgId();
+ }
+
+ @Override
+ public String getFullName() {
+ return (_oleObject == null) ? null : _oleObject.getName();
+ }
+
+
+ /**
+ * Return the data on the (internal) picture.
+ * For an external linked picture, will return null
+ */
+ @Override
+ public XSLFPictureData getPictureData() {
+ if(_data == null){
+ String blipId = getBlipId();
+ if (blipId == null) {
+ return null;
+ }
+
+ PackagePart p = getSheet().getPackagePart();
+ PackageRelationship rel = p.getRelationship(blipId);
+ if (rel != null) {
+ try {
+ PackagePart imgPart = p.getRelatedPart(rel);
+ _data = new XSLFPictureData(imgPart);
+ }
+ catch (Exception e) {
+ throw new POIXMLException(e);
+ }
+ }
+ }
+ return _data;
+ }
+
+ protected CTBlip getBlip(){
+ return getBlipFill().getBlip();
+ }
+
+ protected String getBlipId(){
+ String id = getBlip().getEmbed();
+ if (id.isEmpty()) {
+ return null;
+ }
+ return id;
+ }
+
+ protected CTBlipFillProperties getBlipFill() {
+ String xquery =
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' "
+ + ".//p:blipFill"
+ ;
+ XmlObject xo = selectProperty(XmlObject.class, xquery);
+ try {
+ xo = CTPicture.Factory.parse(xo.getDomNode());
+ } catch (XmlException xe) {
+ return null;
+ }
+ return ((CTPicture)xo).getBlipFill();
+ }
+
+
+ @Override
+ public OutputStream updateObjectData(final Application application, final ObjectMetaData metaData) throws IOException {
+ final ObjectMetaData md = (application != null) ? application.getMetaData() : metaData;
+ if (md == null || md.getClassID() == null) {
+ throw new IllegalArgumentException("either application and/or metaData needs to be set.");
+ }
+
+
+ final XSLFSheet sheet = getSheet();
+
+ final RelationPart rp;
+ if (_oleObject.isSetId()) {
+ // object data was already set
+ rp = sheet.getRelationPartById(_oleObject.getId());
+ } else {
+ // object data needs to be initialized
+ try {
+ final XSLFRelation descriptor = XSLFRelation.OLE_OBJECT;
+ final OPCPackage pack = sheet.getPackagePart().getPackage();
+ int nextIdx = pack.getUnusedPartIndex(descriptor.getDefaultFileName());
+ rp = sheet.createRelationship(descriptor, XSLFFactory.getInstance(), nextIdx, false);
+ _oleObject.setId(rp.getRelationship().getId());
+ } catch (InvalidFormatException e) {
+ throw new IOException("Unable to add new ole embedding", e);
+ }
+
+ // setting spid only works with a vml drawing object
+ // oleObj.setSpid("_x0000_s"+(1025+objectIdx));
+ }
+
+ _oleObject.setProgId(md.getProgId());
+ _oleObject.setName(md.getObjectName());
+
+ return new XSLFObjectOutputStream(rp.getDocumentPart().getPackagePart(),md);
+ }
+
+ private static class XSLFObjectOutputStream extends ByteArrayOutputStream {
+ final PackagePart objectPart;
+ final ObjectMetaData metaData;
+ private XSLFObjectOutputStream(final PackagePart objectPart, final ObjectMetaData metaData) {
+ super(100000);
+ this.objectPart = objectPart;
+ this.metaData = metaData;
+ }
+
+ public void close() throws IOException {
+ objectPart.clear();
+ try (final OutputStream os = objectPart.getOutputStream()) {
+ final ByteArrayInputStream bis = new ByteArrayInputStream(this.buf, 0, size());
+ final FileMagic fm = FileMagic.valueOf(this.buf);
+
+ if (fm == FileMagic.OLE2) {
+ try (final POIFSFileSystem poifs = new POIFSFileSystem(bis)) {
+ poifs.getRoot().setStorageClsid(metaData.getClassID());
+ poifs.writeFilesystem(os);
+ }
+ } else if (metaData.getOleEntry() == null) {
+ // OLE Name hasn't been specified, pass the input through
+ os.write(this.buf, 0, size());
+ } else {
+ try (final POIFSFileSystem poifs = new POIFSFileSystem()) {
+ final ClassID clsId = metaData.getClassID();
+ if (clsId != null) {
+ poifs.getRoot().setStorageClsid(clsId);
+ }
+ poifs.createDocument(bis, metaData.getOleEntry());
+
+ Ole10Native.createOleMarkerEntry(poifs);
+
+ poifs.writeFilesystem(os);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ *
+ *
+ * @param shapeId 1-based shapeId
+ * @param picRel relationship to the picture data in the ooxml package
+ * @return
+ */
+ static CTGraphicalObjectFrame prototype(int shapeId, String picRel){
+ CTGraphicalObjectFrame frame = CTGraphicalObjectFrame.Factory.newInstance();
+ CTGraphicalObjectFrameNonVisual nvGr = frame.addNewNvGraphicFramePr();
+
+ CTNonVisualDrawingProps cnv = nvGr.addNewCNvPr();
+ // usually the shape name has its index based on the n-th embeding, but having
+ // the prototype separate from the actual updating of the object, we use the shape id
+ cnv.setName("Object " + (shapeId + 1));
+ cnv.setId(shapeId + 1);
+
+ // add empty property elements otherwise Powerpoint doesn't load the file ...
+ nvGr.addNewCNvGraphicFramePr();
+ nvGr.addNewNvPr();
+
+ frame.addNewXfrm();
+ CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
+ gr.setUri(OLE_URI);
+ XmlCursor grCur = gr.newCursor();
+ grCur.toEndToken();
+ grCur.beginElement(new QName(PML_NS, "oleObj"));
+ grCur.insertElement(new QName(PML_NS, "embed"));
+
+
+ CTGroupShape grpShp = CTGroupShape.Factory.newInstance();
+ CTPicture pic = grpShp.addNewPic();
+ CTPictureNonVisual nvPicPr = pic.addNewNvPicPr();
+ CTNonVisualDrawingProps cNvPr = nvPicPr.addNewCNvPr();
+ cNvPr.setName("");
+ cNvPr.setId(0);
+ nvPicPr.addNewCNvPicPr();
+ nvPicPr.addNewNvPr();
+
+
+ CTBlipFillProperties blip = pic.addNewBlipFill();
+ blip.addNewBlip().setEmbed(picRel);
+ blip.addNewStretch().addNewFillRect();
+
+ CTShapeProperties spPr = pic.addNewSpPr();
+ CTTransform2D xfrm = spPr.addNewXfrm();
+ CTPoint2D off = xfrm.addNewOff();
+ off.setX(1270000);
+ off.setY(1270000);
+ CTPositiveSize2D xext = xfrm.addNewExt();
+ xext.setCx(1270000);
+ xext.setCy(1270000);
+
+ spPr.addNewPrstGeom().setPrst(STShapeType.RECT);
+
+
+ XmlCursor picCur = grpShp.newCursor();
+ picCur.toStartDoc();
+ picCur.moveXmlContents(grCur);
+ picCur.dispose();
+
+ grCur.dispose();
+
+
+ return frame;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
index 3285b67382..54ede09133 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
@@ -231,6 +231,14 @@ public class XSLFRelation extends POIXMLRelation {
XSLFTableStyles.class
);
+ public static final XSLFRelation OLE_OBJECT = new XSLFRelation(
+ "application/vnd.openxmlformats-officedocument.oleObject",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject",
+ "/ppt/embeddings/oleObject#.bin",
+ XSLFObjectData.class
+ );
+
+
private XSLFRelation(String type, String rel, String defaultName, Class<? extends POIXMLDocumentPart> cls) {
super(type, rel, defaultName, cls);
_table.put(rel, this);
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
index 6a8ea9ce78..89617009c7 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
@@ -18,6 +18,7 @@ package org.apache.poi.xslf.usermodel;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
+import java.awt.Dimension;
import java.awt.Graphics2D;
import java.io.IOException;
import java.io.InputStream;
@@ -45,13 +46,23 @@ import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.Sheet;
-import org.apache.poi.util.*;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlCursor;
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.presentationml.x2006.main.*;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTOleObject;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
@Beta
public abstract class XSLFSheet extends POIXMLDocumentPart
@@ -256,6 +267,28 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
}
+ @Override
+ public XSLFObjectShape createOleShape(PictureData pictureData) {
+ if (!(pictureData instanceof XSLFPictureData)) {
+ throw new IllegalArgumentException("pictureData needs to be of type XSLFPictureData");
+ }
+ XSLFPictureData xPictureData = (XSLFPictureData)pictureData;
+ PackagePart pic = xPictureData.getPackagePart();
+
+ RelationPart rp = addRelation(null, XSLFRelation.IMAGES, new XSLFPictureData(pic));
+
+ XSLFObjectShape sh = getDrawing().createOleShape(rp.getRelationship().getId());
+ CTOleObject oleObj = sh.getCTOleObject();
+ Dimension dim = pictureData.getImageDimension();
+ oleObj.setImgW(Units.toEMU(dim.getWidth()));
+ oleObj.setImgH(Units.toEMU(dim.getHeight()));
+
+
+ getShapes().add(sh);
+ sh.setParent(this);
+ return sh;
+ }
+
/**
* Returns an iterator over the shapes in this sheet
*
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
index f1269a7995..86b81d682a 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
@@ -59,24 +59,27 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
XmlCursor xc = god.newCursor();
- if (!xc.toChild(DRAWINGML_URI, "tbl")) {
- throw new IllegalStateException("a:tbl element was not found in\n " + god);
- }
-
- XmlObject xo = xc.getObject();
- // Pesky XmlBeans bug - see Bugzilla #49934
- // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
- if (xo instanceof XmlAnyTypeImpl){
- String errStr =
- "Schemas (*.xsb) for CTTable can't be loaded - usually this happens when OSGI " +
- "loading is used and the thread context classloader has no reference to " +
- "the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
- "e.g. with CTTable.class.getClassLoader()"
- ;
- throw new IllegalStateException(errStr);
+ try {
+ if (!xc.toChild(DRAWINGML_URI, "tbl")) {
+ throw new IllegalStateException("a:tbl element was not found in\n " + god);
+ }
+
+ XmlObject xo = xc.getObject();
+ // Pesky XmlBeans bug - see Bugzilla #49934
+ // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
+ if (xo instanceof XmlAnyTypeImpl){
+ String errStr =
+ "Schemas (*.xsb) for CTTable can't be loaded - usually this happens when OSGI " +
+ "loading is used and the thread context classloader has no reference to " +
+ "the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
+ "e.g. with CTTable.class.getClassLoader()"
+ ;
+ throw new IllegalStateException(errStr);
+ }
+ _table = (CTTable)xo;
+ } finally {
+ xc.dispose();
}
- _table = (CTTable)xo;
- xc.dispose();
_rows = new ArrayList<>(_table.sizeOfTrArray());
for(CTTableRow row : _table.getTrArray()) {
diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java b/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java
new file mode 100644
index 0000000000..cd482f9a08
--- /dev/null
+++ b/src/ooxml/testcases/org/apache/poi/sl/TestOleShape.java
@@ -0,0 +1,220 @@
+/* ====================================================================
+ 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.sl;
+
+import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V12;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.EXCEL_V8;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.PDF;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V12;
+import static org.apache.poi.sl.usermodel.ObjectMetaData.Application.WORD_V8;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.poifs.storage.RawDataUtil;
+import org.apache.poi.sl.usermodel.ObjectMetaData;
+import org.apache.poi.sl.usermodel.ObjectShape;
+import org.apache.poi.sl.usermodel.PictureData;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TestOleShape {
+ private static final String PDF_SAMPLE =
+ "H4sIAAAAAAAAAJWUezRUWxzHe+o2FXncVtxLpxi3FPOeKYspjMdM5J1S4TTOaDIzxzpzJo9CUrnrSiUxIeT" +
+ "9jB7yqInihrhepTwqt1AT5VZCC7XcY0LWcv+5Z521zz6fvX+/vb/7t9cX78CyMiQZ0XD4W4OFEzgKQATgg4" +
+ "dxJiYAwRYS+aCHACqGnHAAABCs+AIUQrCvAEQhFsSFvSEck4kTowgECnEBl6E4OxGesfLkl2Bc0g5V/MCHt" +
+ "duqroTFC27YIKGAp+OL5Ou1SsmebA1XvciLk+Ucg84aLclQZhRZmh0amrG9Ina4t7Lh+ZCAHyezsg/NXsZg" +
+ "vuPw8NIedsrI2sZlz2vfhLkZfIgfMr4zFvTrmfbRgMmPw1UTvWk+r4MCZfLtj2WPPStVJ0P2PiKkxo+YnJ5" +
+ "Ua7v5UnefkB9ev0vSR37a8NrsC2lApaLp7086wS3Lzi2LqB3TMW2POrdRRUYMFYWs8vBo/kSQ6dYXpR6rxM" +
+ "UXM0vqu4arpe5dha7XS5MYS5P1arVG653sb8pXqReVw/TfjK8R3q4Z7X7Uk9dZ2Bcl8Wpmsl80Xf1QTOxe3" +
+ "Nutwus0kYge1LoHvgKLbc/f6WvdcsBfS9ctU3vSaneHNm0w/uhrm0Zett5O83s2xh2Gm8WZfWJ+/CNWruZ2" +
+ "cap8tR2/U9bAfRBbYt3PL9jvb3+0usqSF6vfrFuEq8Hf6jgrx/fERpZJEjKbHtJ11jCdUwI7Oc8QrmZf2pr" +
+ "L43WJn1mlT1ydV+QbrndcdN3qSEnicVhmoJyfWyprUEsIZlPyvi0tiEy7FzkOnqlE/qC6xFSpyg0E8tODa7" +
+ "qiKX61hMxRkZt73ITLWIHwtZtj71NbS4/BgKHnssOMcXOp1aacX4A//V+VFN4TWl6QryxdkcAp79BZcipmP" +
+ "OWOWkS6KhqUWlG+yCCxVMMtfW+9e56++gKHYEs9PNJztTI6KtyfOCDPOBppt3udRs3NpGrKfrs3i3Nivtrs" +
+ "VTl5LFerXZlTbf5XumbeYsOfwnve5ksEjKy6s1Z78rpbeJq7biTdzWwU3vhZ1GqkYb9D+t6mYvWLhXn6FWi" +
+ "c60VWpbBtVYHLQkmbh6Txwm6Ul3LbNW/Hs5FtLnlNX3fsAX2jPdlOI5W3HDIcm2MyNiR39rdyHlpwusjoOj" +
+ "I3IKfgPMILSzHZInmQaWyUFXEi0bHsCLX8pm9Gzl2vou7E3rrkPYdt1EwW3R5Qcg8rwzk88c1p13l8v+WkY" +
+ "75FHeS7XrvRsHgLy+wfr2EBRfNJ/4UVhUrihRqDktXciPGxWv1eXs396/0lqWG3YtU/A+D90hrT46cumSUN" +
+ "rBdG0G2Knn3T9Kw0X96vbhxMyr92uqUNOa4aEnGqP8us6GULm7mIyFKuxnOW2MZEEuKXmOpxnnqlwiMn+ju" +
+ "Xu+inC5mpG9oesxKkhcJq9bra5vR3H7l10hGbAxqu6t0LvHzaDnPIp/zeu0iXj1NNtVc+cMyUsH18u7TGXJ" +
+ "XiL4W3tqaL2mq6zkgXWB6kOTB3RxW8PHAOvzfaufDptdg7qmZlEcrUzbd5jKtVb85Sr9jaMT8a3y2Q30+3/" +
+ "FrsfGZDblh/mYnHhCg3ekm2q1JIYEVCd9rv42PNb9RFpuSsa4MNE0GfdSYDv6lsudikg4NE3tNugfWmfIY6" +
+ "7TeYvZCItG0zmDxrQwrjsQxArZ1RzHSA72CKgURgyqQszAASQOCCWItZETaAtdg7nYc2x85cAv0ggOAA+kC" +
+ "KnA4gAolQLGzG3ewgbz5oDgcA+zBEBEhUkhGDQiZvpc3tHlBMtYBFKBYsBiiz0dYILPGbs73vqynoDHLGKA" +
+ "KKxH5TK3MDZzAbQBEJNPNngc1iQUf4XMjJ2nxazxR3gsSwBOFCYoCsWPOHRtJ/ahQronbyvcWYnqljcJrdu" +
+ "2RK9pwE9DkJLLDioDACbOSCfAQGSEYkqhGJCGw8hKJ+xgSCgvogoN8hPldsBCM+mzZ9P0wE9pZwof8V92MD" +
+ "jHkKLEAUFMA+04XC1EzX6UdMAALxcERgK444+wB0Go1CA3jANCNRGdj1UoyIZhlpPsMobf48GmkeI1Pp8xi" +
+ "Nsm0eo9O3/mAoAvIFEKIQ58wPgrAtK+oJwyjAmL0+bBEPBugzGsUoiKAKhSQGmYjD4y3trXD/AmBc9IeqBwAA";
+
+ enum Api { HSLF, XSLF };
+
+
+ @Parameter(value = 0)
+ public Api api;
+ @Parameter(value = 1)
+ public ObjectMetaData.Application app;
+
+
+ private static File pictureFile;
+
+ @BeforeClass
+ public static void initPicture() {
+ pictureFile = POIDataSamples.getSlideShowInstance().getFile("wrench.emf");
+ }
+
+
+ @Parameters(name="{0} {1}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ { Api.HSLF, EXCEL_V8 },
+ { Api.HSLF, WORD_V8 },
+ { Api.HSLF, PDF },
+ { Api.XSLF, EXCEL_V12 },
+ { Api.XSLF, WORD_V12 },
+ { Api.XSLF, PDF },
+ });
+ }
+
+ @Test
+ public void embedData() throws IOException, InvalidFormatException {
+ final ByteArrayInputStream pptBytes;
+ try (SlideShow<?,?> ppt = createSlideShow()) {
+ final PictureData picData = ppt.addPicture(pictureFile, PictureType.EMF);
+ final Slide<?,?> slide = ppt.createSlide();
+ final ObjectShape<?,?> oleShape = slide.createOleShape(picData);
+ oleShape.setAnchor(new Rectangle2D.Double(100,100,100,100));
+ try (OutputStream os = oleShape.updateObjectData(app, null)) {
+ fillOleData(os);
+ }
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream(50000);
+ ppt.write(bos);
+ pptBytes = new ByteArrayInputStream(bos.toByteArray());
+ }
+ try (SlideShow<?,?> ppt = SlideShowFactory.create(pptBytes)) {
+ final ObjectShape<?,?> oleShape = (ObjectShape<?,?>)ppt.getSlides().get(0).getShapes().get(0);
+ try (InputStream bis = oleShape.readObjectData()) {
+ validateOleData(bis);
+ }
+ }
+ }
+
+ private SlideShow<?,?> createSlideShow() {
+ if (api == Api.XSLF) {
+ return new XMLSlideShow();
+ } else {
+ assumeFalse(xslfOnly());
+ return new HSLFSlideShow();
+ }
+ }
+
+
+ private void fillOleData(final OutputStream out) throws IOException {
+ switch (app) {
+ case EXCEL_V8:
+ case EXCEL_V12:
+ try (Workbook wb = (app == EXCEL_V12) ? new XSSFWorkbook() : new HSSFWorkbook()) {
+ wb.createSheet().createRow(0).createCell(0).setCellValue("test me");
+ wb.write(out);
+ }
+ break;
+ case WORD_V8:
+ try (InputStream is = POIDataSamples.getDocumentInstance().openResourceAsStream("simple.doc")) {
+ IOUtils.copy(is, out);
+ }
+ break;
+ case WORD_V12:
+ try (XWPFDocument doc = new XWPFDocument()) {
+ doc.createParagraph().createRun().setText("Test me");
+ doc.write(out);
+ }
+ break;
+ case PDF:
+ out.write(RawDataUtil.decompress(PDF_SAMPLE));
+ break;
+ default:
+ case CUSTOM:
+ fail("not implemented");
+ break;
+ }
+ }
+
+ private void validateOleData(final InputStream in) throws IOException, InvalidFormatException {
+ switch (app) {
+ case EXCEL_V8:
+ case EXCEL_V12:
+ try (Workbook wb = WorkbookFactory.create(in)) {
+ assertEquals("test me", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
+ }
+ break;
+ case WORD_V8:
+ try (HWPFDocument doc = new HWPFDocument(in)) {
+ assertEquals("This is a simple file created with Word 97-SR2.\r", doc.getDocumentText());
+ }
+ break;
+ case WORD_V12:
+ try (XWPFDocument doc = new XWPFDocument(in)) {
+ assertEquals("Test me", doc.getParagraphs().get(0).getText());
+ }
+ break;
+ case PDF:
+ final byte[] expected = RawDataUtil.decompress(PDF_SAMPLE);
+ final byte[] actual = IOUtils.toByteArray(in);
+ assertArrayEquals(expected, actual);
+ break;
+ default:
+ case CUSTOM:
+ fail("not implemented");
+ break;
+ }
+
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java b/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java
index dcdf9c699a..c340808743 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java
@@ -29,7 +29,6 @@ import org.apache.poi.POIOLE2TextExtractor;
import org.apache.poi.hslf.model.Comment;
import org.apache.poi.hslf.model.HSLFMetroShape;
import org.apache.poi.hslf.model.HeadersFooters;
-import org.apache.poi.hslf.model.OLEShape;
import org.apache.poi.hslf.usermodel.HSLFMasterSheet;
import org.apache.poi.hslf.usermodel.HSLFNotes;
import org.apache.poi.hslf.usermodel.HSLFShape;
@@ -41,6 +40,7 @@ import org.apache.poi.hslf.usermodel.HSLFTable;
import org.apache.poi.hslf.usermodel.HSLFTableCell;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
import org.apache.poi.hslf.usermodel.HSLFTextShape;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@@ -194,13 +194,13 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor {
return getText(false, true);
}
- public List<OLEShape> getOLEShapes() {
- List<OLEShape> list = new ArrayList<>();
+ public List<HSLFObjectShape> getOLEShapes() {
+ List<HSLFObjectShape> list = new ArrayList<>();
for (HSLFSlide slide : _slides) {
for (HSLFShape shape : slide.getShapes()) {
- if (shape instanceof OLEShape) {
- list.add((OLEShape) shape);
+ if (shape instanceof HSLFObjectShape) {
+ list.add((HSLFObjectShape) shape);
}
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
index 7903bb32d4..2449adb6c9 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
@@ -17,8 +17,8 @@
package org.apache.poi.hslf.record;
-import java.io.OutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
@@ -31,7 +31,7 @@ public class ExEmbed extends RecordContainer {
/**
* Record header data.
*/
- private byte[] _header;
+ private final byte[] _header;
// Links to our more interesting children
private RecordAtom embedAtom;
@@ -47,7 +47,7 @@ public class ExEmbed extends RecordContainer {
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
- protected ExEmbed(byte[] source, int start, int len) {
+ protected ExEmbed(final byte[] source, final int start, final int len) {
// Grab the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
@@ -62,7 +62,7 @@ public class ExEmbed extends RecordContainer {
*
* @param embedAtom the new embedAtom
*/
- protected ExEmbed(RecordAtom embedAtom) {
+ protected ExEmbed(final RecordAtom embedAtom) {
this();
_children[0] = this.embedAtom = embedAtom;
}
@@ -81,11 +81,11 @@ public class ExEmbed extends RecordContainer {
LittleEndian.putShort(_header, 2, (short)getRecordType());
// Setup our child records
- CString cs1 = new CString();
+ final CString cs1 = new CString();
cs1.setOptions(0x1 << 4);
- CString cs2 = new CString();
+ final CString cs2 = new CString();
cs2.setOptions(0x2 << 4);
- CString cs3 = new CString();
+ final CString cs3 = new CString();
cs3.setOptions(0x3 << 4);
_children[0] = new ExEmbedAtom();
_children[1] = new ExOleObjAtom();
@@ -117,8 +117,8 @@ public class ExEmbed extends RecordContainer {
for (int i = 2; i < _children.length; i++) {
if (_children[i] instanceof CString){
- CString cs = (CString)_children[i];
- int opts = cs.getOptions() >> 4;
+ final CString cs = (CString)_children[i];
+ final int opts = cs.getOptions() >> 4;
switch(opts){
case 0x1: menuName = cs; break;
case 0x2: progId = cs; break;
@@ -134,8 +134,7 @@ public class ExEmbed extends RecordContainer {
*
* @return the {@link ExEmbedAtom}.
*/
- public ExEmbedAtom getExEmbedAtom()
- {
+ public ExEmbedAtom getExEmbedAtom() {
return (ExEmbedAtom)embedAtom;
}
@@ -144,8 +143,7 @@ public class ExEmbed extends RecordContainer {
*
* @return the {@link ExOleObjAtom}.
*/
- public ExOleObjAtom getExOleObjAtom()
- {
+ public ExOleObjAtom getExOleObjAtom() {
return oleObjAtom;
}
@@ -154,14 +152,13 @@ public class ExEmbed extends RecordContainer {
*
* @return the name used for menus and the Links dialog box.
*/
- public String getMenuName()
- {
+ public String getMenuName() {
return menuName == null ? null : menuName.getText();
}
- public void setMenuName(String s)
- {
- if(menuName != null) menuName.setText(s);
+ public void setMenuName(final String menuName) {
+ this.menuName = safeCString(this.menuName, 0x1);
+ this.menuName.setText(menuName);
}
/**
@@ -169,28 +166,29 @@ public class ExEmbed extends RecordContainer {
*
* @return the OLE Programmatic Identifier.
*/
- public String getProgId()
- {
+ public String getProgId() {
return progId == null ? null : progId.getText();
}
- public void setProgId(String s)
- {
- if(progId != null) progId.setText(s);
+ public void setProgId(final String progId) {
+ this.progId = safeCString(this.progId, 0x2);
+ this.progId.setText(progId);
}
+
+
+
/**
* Gets the name that appears in the paste special dialog.
*
* @return the name that appears in the paste special dialog.
*/
- public String getClipboardName()
- {
+ public String getClipboardName() {
return clipboardName == null ? null : clipboardName.getText();
}
- public void setClipboardName(String s)
- {
- if(clipboardName != null) clipboardName.setText(s);
+ public void setClipboardName(final String clipboardName) {
+ this.clipboardName = safeCString(this.clipboardName, 0x3);
+ this.clipboardName.setText(clipboardName);
}
/**
@@ -199,6 +197,7 @@ public class ExEmbed extends RecordContainer {
*
* @return the record type.
*/
+ @Override
public long getRecordType() {
return RecordTypes.ExEmbed.typeID;
}
@@ -210,7 +209,31 @@ public class ExEmbed extends RecordContainer {
* @param out the output stream.
* @throws IOException if there was an error writing to the stream.
*/
- public void writeOut(OutputStream out) throws IOException {
+ @Override
+ public void writeOut(final OutputStream out) throws IOException {
writeOut(_header[0],_header[1],getRecordType(),_children,out);
}
+
+ private CString safeCString(CString oldStr, int optionsId) {
+ CString newStr = oldStr;
+ if (newStr == null) {
+ newStr = new CString();
+ newStr.setOptions(optionsId << 4);
+ }
+
+ boolean found = false;
+ for (final Record r : _children) {
+ // for simplicity just check for object identity
+ if (r == newStr) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ appendChildRecord(newStr);
+ }
+
+ return newStr;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
index 27f5cbaf5b..b47373899a 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
@@ -39,8 +39,6 @@ import org.apache.poi.util.Units;
/**
* Represents a group of shapes.
- *
- * @author Yegor Kozlov
*/
public class HSLFGroupShape extends HSLFShape
implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
@@ -362,4 +360,15 @@ implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
addShape(s);
return s;
}
+
+ @Override
+ public HSLFObjectShape createOleShape(PictureData pictureData) {
+ if (!(pictureData instanceof HSLFPictureData)) {
+ throw new IllegalArgumentException("pictureData needs to be of type HSLFPictureData");
+ }
+ HSLFObjectShape s = new HSLFObjectShape((HSLFPictureData)pictureData, this);
+ s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100));
+ addShape(s);
+ return s;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
index f02ddbe785..b1cb5a4324 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
@@ -16,17 +16,25 @@
==================================================================== */
package org.apache.poi.hslf.usermodel;
-import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import org.apache.poi.hslf.record.ExOleObjStg;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectData;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
/**
* A class that represents object data embedded in a slide show.
- *
- * @author Daniel Noll
*/
-public class HSLFObjectData {
+public class HSLFObjectData implements ObjectData {
+ private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectData.class);
+
/**
* The record that contains the object data.
*/
@@ -41,14 +49,19 @@ public class HSLFObjectData {
this.storage = storage;
}
- /**
- * Gets an input stream which returns the binary of the embedded data.
- *
- * @return the input stream which will contain the binary of the embedded data.
- */
- public InputStream getData() {
+ @Override
+ public InputStream getInputStream() {
return storage.getData();
}
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return new ByteArrayOutputStream(100000) {
+ public void close() throws IOException {
+ setData(getBytes());
+ }
+ };
+ }
/**
* Sets the embedded data.
@@ -67,4 +80,15 @@ public class HSLFObjectData {
public ExOleObjStg getExOleObjStg() {
return storage;
}
+
+
+ @Override
+ public String getOLE2ClassName() {
+ return null;
+ }
+
+ @Override
+ public String getFileName() {
+ return null;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java
index 23c4daa203..ffe2c51b04 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectShape.java
@@ -15,7 +15,12 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hslf.model;
+package org.apache.poi.hslf.usermodel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties;
@@ -26,22 +31,22 @@ import org.apache.poi.hslf.record.ExObjRefAtom;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordTypes;
-import org.apache.poi.hslf.usermodel.HSLFObjectData;
-import org.apache.poi.hslf.usermodel.HSLFPictureData;
-import org.apache.poi.hslf.usermodel.HSLFPictureShape;
-import org.apache.poi.hslf.usermodel.HSLFShape;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+import org.apache.poi.poifs.filesystem.FileMagic;
+import org.apache.poi.poifs.filesystem.Ole10Native;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.sl.usermodel.ObjectMetaData;
+import org.apache.poi.sl.usermodel.ObjectMetaData.Application;
+import org.apache.poi.sl.usermodel.ObjectShape;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
- * A shape representing embedded OLE obejct.
+ * A shape representing embedded OLE object.
*/
-public final class OLEShape extends HSLFPictureShape {
- private static final POILogger LOG = POILogFactory.getLogger(OLEShape.class);
+public final class HSLFObjectShape extends HSLFPictureShape implements ObjectShape<HSLFShape,HSLFTextParagraph> {
+ private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectShape.class);
private ExEmbed _exEmbed;
@@ -50,7 +55,7 @@ public final class OLEShape extends HSLFPictureShape {
*
* @param data the picture data
*/
- public OLEShape(HSLFPictureData data){
+ public HSLFObjectShape(HSLFPictureData data){
super(data);
}
@@ -60,7 +65,7 @@ public final class OLEShape extends HSLFPictureShape {
* @param data the picture data
* @param parent the parent shape
*/
- public OLEShape(HSLFPictureData data, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) {
+ public HSLFObjectShape(HSLFPictureData data, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) {
super(data, parent);
}
@@ -71,7 +76,7 @@ public final class OLEShape extends HSLFPictureShape {
* this picture in the <code>Slide</code>
* @param parent the parent shape of this picture
*/
- public OLEShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
+ public HSLFObjectShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
super(escherRecord, parent);
}
@@ -87,12 +92,12 @@ public final class OLEShape extends HSLFPictureShape {
/**
* Set the unique identifier for the OLE object and
* register it in the necessary structures
- *
+ *
* @param objectId the unique identifier for the OLE object
*/
public void setObjectID(int objectId){
setEscherProperty(EscherProperties.BLIP__PICTUREID, objectId);
-
+
EscherContainerRecord ecr = getSpContainer();
EscherSpRecord spRecord = ecr.getChildById(EscherSpRecord.RECORD_ID);
spRecord.setFlags(spRecord.getFlags()|EscherSpRecord.FLAG_OLESHAPE);
@@ -111,14 +116,13 @@ public final class OLEShape extends HSLFPictureShape {
}
uer.setExObjIdRef(objectId);
}
-
-
+
+
/**
* Returns unique identifier for the OLE object.
*
* @return the unique identifier for the OLE object
*/
- @SuppressWarnings("resource")
public HSLFObjectData getObjectData(){
HSLFSlideShow ppt = getSheet().getSlideShow();
HSLFObjectData[] ole = ppt.getEmbeddedObjects();
@@ -129,9 +133,10 @@ public final class OLEShape extends HSLFPictureShape {
if(exEmbed != null) {
int ref = exEmbed.getExOleObjAtom().getObjStgDataRef();
- for (int i = 0; i < ole.length; i++) {
- if(ole[i].getExOleObjStg().getPersistId() == ref) {
- data=ole[i];
+ for (HSLFObjectData hod : ole) {
+ if(hod.getExOleObjStg().getPersistId() == ref) {
+ data=hod;
+ // keep searching to return the last persistent object with that refId
}
}
}
@@ -156,29 +161,40 @@ public final class OLEShape extends HSLFPictureShape {
* 6. MetaFile( 4033), optional
* </p>
*/
- @SuppressWarnings("resource")
public ExEmbed getExEmbed(){
- if(_exEmbed == null){
+ return getExEmbed(false);
+ }
+
+ private ExEmbed getExEmbed(boolean create) {
+ if (_exEmbed == null) {
HSLFSlideShow ppt = getSheet().getSlideShow();
- ExObjList lst = ppt.getDocumentRecord().getExObjList(false);
+ ExObjList lst = ppt.getDocumentRecord().getExObjList(create);
if(lst == null){
LOG.log(POILogger.WARN, "ExObjList not found");
return null;
}
int id = getObjectID();
- Record[] ch = lst.getChildRecords();
- for (int i = 0; i < ch.length; i++) {
- if(ch[i] instanceof ExEmbed){
- ExEmbed embd = (ExEmbed)ch[i];
- if( embd.getExOleObjAtom().getObjID() == id) _exEmbed = embd;
+ for (Record ch : lst.getChildRecords()) {
+ if(ch instanceof ExEmbed){
+ ExEmbed embd = (ExEmbed)ch;
+ if( embd.getExOleObjAtom().getObjID() == id) {
+ _exEmbed = embd;
+ }
}
}
+
+ if (_exEmbed == null && create) {
+ _exEmbed = new ExEmbed();
+ _exEmbed.getExOleObjAtom().setObjID(id);
+ lst.appendChildRecord(_exEmbed);
+ }
}
return _exEmbed;
}
-
+
+
/**
* Returns the instance name of the embedded object, e.g. "Document" or "Workbook".
*
@@ -189,26 +205,63 @@ public final class OLEShape extends HSLFPictureShape {
return (ee == null) ? null : ee.getMenuName();
}
- /**
- * Returns the full name of the embedded object,
- * e.g. "Microsoft Word Document" or "Microsoft Office Excel Worksheet".
- *
- * @return the full name of the embedded object
- */
+ @Override
public String getFullName(){
ExEmbed ee = getExEmbed();
return (ee == null) ? null : ee.getClipboardName();
}
- /**
- * Returns the ProgID that stores the OLE Programmatic Identifier.
- * A ProgID is a string that uniquely identifies a given object, for example,
- * "Word.Document.8" or "Excel.Sheet.8".
- *
- * @return the ProgID
- */
- public String getProgID(){
+ public void setFullName(final String fullName) {
+ getExEmbed(true).setClipboardName(fullName);
+ }
+
+ @Override
+ public String getProgId(){
ExEmbed ee = getExEmbed();
return (ee == null) ? null : ee.getProgId();
}
+
+ public void setProgId(final String progId) {
+ getExEmbed(true).setProgId(progId);
+ }
+
+ public OutputStream updateObjectData(final Application application, final ObjectMetaData metaData) throws IOException {
+ final ObjectMetaData md = (application != null) ? application.getMetaData() : metaData;
+ if (md == null) {
+ throw new RuntimeException("either application or metaData needs to be set");
+ }
+
+ return new ByteArrayOutputStream(100000) {
+ public void close() throws IOException {
+ final FileMagic fm = FileMagic.valueOf(this.buf);
+ final ByteArrayInputStream bis = new ByteArrayInputStream(this.buf, 0, this.count);
+ final HSLFSlideShow ppt = getSheet().getSlideShow();
+
+ try (POIFSFileSystem poifs = (fm == FileMagic.OLE2) ? new POIFSFileSystem(bis) : new POIFSFileSystem()) {
+ if (fm != FileMagic.OLE2) {
+ poifs.createDocument(bis, md.getOleEntry());
+ }
+
+ Ole10Native.createOleMarkerEntry(poifs);
+
+ poifs.getRoot().setStorageClsid(md.getClassID());
+
+
+ int oid = getObjectID();
+ if (oid == 0) {
+ // assign new embedding
+ oid = ppt.addEmbed(poifs);
+ setObjectID(oid);
+ } else {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(this.size()+1000);
+ poifs.writeFilesystem(bos);
+ getObjectData().setData(bos.toByteArray());
+ }
+
+ setProgId(md.getProgId());
+ setFullName(md.getObjectName());
+ }
+ }
+ };
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java
index 8152befe25..47c895e0e3 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeContainer.java
@@ -45,5 +45,6 @@ public interface HSLFShapeContainer extends ShapeContainer<HSLFShape,HSLFTextPar
@Override
HSLFPictureShape createPicture(PictureData pictureData);
-
+ @Override
+ HSLFObjectShape createOleShape(PictureData pictureData);
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
index 4797ff5f57..58e216a4f5 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
@@ -31,7 +31,6 @@ import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hslf.model.MovieShape;
-import org.apache.poi.hslf.model.OLEShape;
import org.apache.poi.hslf.record.ExObjRefAtom;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.InteractiveInfo;
@@ -134,7 +133,7 @@ public final class HSLFShapeFactory {
if(info != null && info.getInteractiveInfoAtom() != null){
switch(info.getInteractiveInfoAtom().getAction()){
case InteractiveInfoAtom.ACTION_OLE:
- return new OLEShape(spContainer, parent);
+ return new HSLFObjectShape(spContainer, parent);
case InteractiveInfoAtom.ACTION_MEDIA:
return new MovieShape(spContainer, parent);
default:
@@ -144,7 +143,7 @@ public final class HSLFShapeFactory {
ExObjRefAtom oes = getClientDataRecord(spContainer, RecordTypes.ExObjRefAtom.typeID);
return (oes != null)
- ? new OLEShape(spContainer, parent)
+ ? new HSLFObjectShape(spContainer, parent)
: new HSLFPictureShape(spContainer, parent);
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java
index c37d47713f..be026cb3f9 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java
@@ -442,4 +442,15 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
addShape(s);
return s;
}
+
+ @Override
+ public HSLFObjectShape createOleShape(PictureData pictureData) {
+ if (!(pictureData instanceof HSLFPictureData)) {
+ throw new IllegalArgumentException("pictureData needs to be of type HSLFPictureData");
+ }
+ HSLFObjectShape s = new HSLFObjectShape((HSLFPictureData)pictureData);
+ s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100));
+ addShape(s);
+ return s;
+ }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java b/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java
index 281173e23f..f2700d4fac 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java
@@ -33,9 +33,9 @@ import java.io.InputStream;
import java.util.List;
import org.apache.poi.POIDataSamples;
-import org.apache.poi.hslf.model.OLEShape;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.poifs.filesystem.DirectoryNode;
@@ -206,12 +206,12 @@ public final class TestExtractor {
@Test
public void testExtractFromOwnEmbeded() throws IOException {
PowerPointExtractor ppe = openExtractor("ppt_with_embeded.ppt");
- List<OLEShape> shapes = ppe.getOLEShapes();
+ List<HSLFObjectShape> shapes = ppe.getOLEShapes();
assertEquals("Expected 6 ole shapes", 6, shapes.size());
int num_ppt = 0, num_doc = 0, num_xls = 0;
- for (OLEShape ole : shapes) {
+ for (HSLFObjectShape ole : shapes) {
String name = ole.getInstanceName();
- InputStream data = ole.getObjectData().getData();
+ InputStream data = ole.getObjectData().getInputStream();
if ("Worksheet".equals(name)) {
HSSFWorkbook wb = new HSSFWorkbook(data);
num_xls++;
@@ -239,8 +239,8 @@ public final class TestExtractor {
@Test
public void test52991() throws IOException {
PowerPointExtractor ppe = openExtractor("badzip.ppt");
- for (OLEShape shape : ppe.getOLEShapes()) {
- IOUtils.copy(shape.getObjectData().getData(), new ByteArrayOutputStream());
+ for (HSLFObjectShape shape : ppe.getOLEShapes()) {
+ IOUtils.copy(shape.getObjectData().getInputStream(), new ByteArrayOutputStream());
}
ppe.close();
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java
index d8c331b7fd..16f40a72f7 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java
@@ -35,6 +35,7 @@ import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument;
@@ -70,7 +71,7 @@ public final class TestOleEmbedding {
HSLFObjectData[] objects = slideShow.getEmbeddedObjects();
assertEquals("Should be two objects", 2, objects.length);
for (HSLFObjectData od : objects) {
- long checkEMF = IOUtils.calculateChecksum(od.getData());
+ long checkEMF = IOUtils.calculateChecksum(od.getInputStream());
assertEquals(checkSums[checkId++], checkEMF);
}
@@ -86,13 +87,13 @@ public final class TestOleEmbedding {
HSLFSlide slide = ppt.getSlides().get(0);
int cnt = 0;
for (HSLFShape sh : slide.getShapes()) {
- if(sh instanceof OLEShape){
+ if(sh instanceof HSLFObjectShape){
cnt++;
- OLEShape ole = (OLEShape)sh;
+ HSLFObjectShape ole = (HSLFObjectShape)sh;
HSLFObjectData data = ole.getObjectData();
if("Worksheet".equals(ole.getInstanceName())){
//Voila! we created a workbook from the embedded OLE data
- HSSFWorkbook wb = new HSSFWorkbook(data.getData());
+ HSSFWorkbook wb = new HSSFWorkbook(data.getInputStream());
HSSFSheet sheet = wb.getSheetAt(0);
//verify we can access the xls data
assertEquals(1, sheet.getRow(0).getCell(0).getNumericCellValue(), 0);
@@ -103,7 +104,7 @@ public final class TestOleEmbedding {
wb.close();
} else if ("Document".equals(ole.getInstanceName())){
//creating a HWPF document
- HWPFDocument doc = new HWPFDocument(data.getData());
+ HWPFDocument doc = new HWPFDocument(data.getInputStream());
String txt = doc.getRange().getParagraph(0).text();
assertEquals("OLE embedding is thoroughly unremarkable.\r", txt);
doc.close();
@@ -129,14 +130,14 @@ public final class TestOleEmbedding {
int oleObjectId1 = ppt.addEmbed(poiData1);
HSLFSlide slide1 = ppt.createSlide();
- OLEShape oleShape1 = new OLEShape(pictData);
+ HSLFObjectShape oleShape1 = new HSLFObjectShape(pictData);
oleShape1.setObjectID(oleObjectId1);
slide1.addShape(oleShape1);
oleShape1.setAnchor(new Rectangle2D.Double(100,100,100,100));
// add second slide with different order in object creation
HSLFSlide slide2 = ppt.createSlide();
- OLEShape oleShape2 = new OLEShape(pictData);
+ HSLFObjectShape oleShape2 = new HSLFObjectShape(pictData);
is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleWithImages.xls");
POIFSFileSystem poiData2 = new POIFSFileSystem(is);
@@ -152,8 +153,8 @@ public final class TestOleEmbedding {
ppt.write(bos);
ppt = new HSLFSlideShow(new ByteArrayInputStream(bos.toByteArray()));
- OLEShape comp = (OLEShape)ppt.getSlides().get(0).getShapes().get(0);
- byte compData[] = IOUtils.toByteArray(comp.getObjectData().getData());
+ HSLFObjectShape comp = (HSLFObjectShape)ppt.getSlides().get(0).getShapes().get(0);
+ byte compData[] = IOUtils.toByteArray(comp.getObjectData().getInputStream());
bos.reset();
poiData1.writeFilesystem(bos);
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java
index 8bb83852e1..df44216093 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java
@@ -1010,7 +1010,7 @@ public final class TestBugs {
long persistId = vbaAtom.getPersistIdRef();
for (HSLFObjectData objData : ppt.getEmbeddedObjects()) {
if (objData.getExOleObjStg().getPersistId() == persistId) {
- VBAMacroReader mr = new VBAMacroReader(objData.getData());
+ VBAMacroReader mr = new VBAMacroReader(objData.getInputStream());
try {
return mr.readMacros();
} finally {