aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/poi/sl/usermodel
diff options
context:
space:
mode:
authorAndreas Beeker <kiwiwings@apache.org>2017-12-31 01:14:08 +0000
committerAndreas Beeker <kiwiwings@apache.org>2017-12-31 01:14:08 +0000
commit704b41ab9a11574bcce25a63c4bf43670389f841 (patch)
treef66d8dd2fd373c1506cf644d9fd648d2225c298f /src/java/org/apache/poi/sl/usermodel
parentcdab1a45110536d6e4abed82152d288b70568d82 (diff)
downloadpoi-704b41ab9a11574bcce25a63c4bf43670389f841.tar.gz
poi-704b41ab9a11574bcce25a63c4bf43670389f841.zip
#61797 - Embed Excel / Ole objects into powerpoint
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1819710 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/poi/sl/usermodel')
-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
4 files changed, 357 insertions, 0 deletions
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);
}