From ed2d78b08b3b8b880a6bb2f27c0664a750c16df2 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 17 Sep 2007 16:30:31 +0000 Subject: [PATCH] When writing out a HSLF file, optionally also write out all the different OLE2 streams, and not just the normal HSLF related ones git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@576505 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/org/apache/poi/POIDocument.java | 78 ++++++++++++++++++ .../org/apache/poi/hslf/HSLFSlideShow.java | 13 ++- .../org/apache/poi/hslf/TestReWrite.java | 35 ++++++++ .../org/apache/poi/hslf/data/WithMacros.ppt | Bin 0 -> 16896 bytes 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 src/scratchpad/testcases/org/apache/poi/hslf/data/WithMacros.ppt diff --git a/src/scratchpad/src/org/apache/poi/POIDocument.java b/src/scratchpad/src/org/apache/poi/POIDocument.java index e8b551d9b..bc3b78dd2 100644 --- a/src/scratchpad/src/org/apache/poi/POIDocument.java +++ b/src/scratchpad/src/org/apache/poi/POIDocument.java @@ -20,13 +20,18 @@ package org.apache.poi; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Iterator; +import java.util.List; import org.apache.poi.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.MutablePropertySet; import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.SummaryInformation; +import org.apache.poi.poifs.filesystem.DirectoryEntry; +import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.DocumentInputStream; +import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -106,11 +111,25 @@ public abstract class POIDocument { * @param outFS the POIFSFileSystem to write the properties into */ protected void writeProperties(POIFSFileSystem outFS) throws IOException { + writeProperties(outFS, null); + } + /** + * Writes out the standard Documment Information Properties (HPSF) + * @param outFS the POIFSFileSystem to write the properties into + * @param writtenEntries a list of POIFS entries to add the property names too + */ + protected void writeProperties(POIFSFileSystem outFS, List writtenEntries) throws IOException { if(sInf != null) { writePropertySet(SummaryInformation.DEFAULT_STREAM_NAME,sInf,outFS); + if(writtenEntries != null) { + writtenEntries.add(SummaryInformation.DEFAULT_STREAM_NAME); + } } if(dsInf != null) { writePropertySet(DocumentSummaryInformation.DEFAULT_STREAM_NAME,dsInf,outFS); + if(writtenEntries != null) { + writtenEntries.add(DocumentSummaryInformation.DEFAULT_STREAM_NAME); + } } } @@ -135,4 +154,63 @@ public abstract class POIDocument { System.err.println("Couldn't write property set with name " + name + " as not supported by HPSF yet"); } } + + /** + * Copies nodes from one POIFS to the other minus the excepts + * @param source is the source POIFS to copy from + * @param target is the target POIFS to copy to + * @param excepts is a list of Strings specifying what nodes NOT to copy + */ + protected void copyNodes(POIFSFileSystem source, POIFSFileSystem target, + List excepts) throws IOException { + //System.err.println("CopyNodes called"); + + DirectoryEntry root = source.getRoot(); + DirectoryEntry newRoot = target.getRoot(); + + Iterator entries = root.getEntries(); + + while (entries.hasNext()) { + Entry entry = (Entry)entries.next(); + if (!isInList(entry.getName(), excepts)) { + copyNodeRecursively(entry,newRoot); + } + } + } + + /** + * Checks to see if the String is in the list, used when copying + * nodes between one POIFS and another + */ + private boolean isInList(String entry, List list) { + for (int k = 0; k < list.size(); k++) { + if (list.get(k).equals(entry)) { + return true; + } + } + return false; + } + + /** + * Copies an Entry into a target POIFS directory, recursively + */ + private void copyNodeRecursively(Entry entry, DirectoryEntry target) + throws IOException { + //System.err.println("copyNodeRecursively called with "+entry.getName()+ + // ","+target.getName()); + DirectoryEntry newTarget = null; + if (entry.isDirectoryEntry()) { + newTarget = target.createDirectory(entry.getName()); + Iterator entries = ((DirectoryEntry)entry).getEntries(); + + while (entries.hasNext()) { + copyNodeRecursively((Entry)entries.next(),newTarget); + } + } else { + DocumentEntry dentry = (DocumentEntry)entry; + DocumentInputStream dstream = new DocumentInputStream(dentry); + target.createDocument(dentry.getName(),dstream); + dstream.close(); + } + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java index 268d6bff0..12afcc49f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java +++ b/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java @@ -383,8 +383,11 @@ public class HSLFSlideShow extends POIDocument // Get a new Filesystem to write into POIFSFileSystem outFS = new POIFSFileSystem(); + // The list of entries we've written out + List writtenEntries = new ArrayList(1); + // Write out the Property Streams - writeProperties(outFS); + writeProperties(outFS, writtenEntries); // For position dependent records, hold where they were and now are @@ -435,6 +438,7 @@ public class HSLFSlideShow extends POIDocument // Write the PPT stream into the POIFS layer ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); outFS.createDocument(bais,"PowerPoint Document"); + writtenEntries.add("PowerPoint Document"); // Update and write out the Current User atom @@ -445,6 +449,7 @@ public class HSLFSlideShow extends POIDocument } currentUser.setCurrentEditOffset(newLastUserEditAtomPos.intValue()); currentUser.writeToFS(outFS); + writtenEntries.add("Current User"); // Write any pictures, into another stream @@ -456,6 +461,12 @@ public class HSLFSlideShow extends POIDocument outFS.createDocument( new ByteArrayInputStream(pict.toByteArray()), "Pictures" ); + writtenEntries.add("Pictures"); + } + + // If requested, write out any other streams we spot + if(preserveNodes) { + copyNodes(filesystem, outFS, writtenEntries); } // Send the POIFSFileSystem object out to the underlying stream diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java b/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java index 01107ebd9..541b7a3a2 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java @@ -37,9 +37,11 @@ public class TestReWrite extends TestCase { // HSLFSlideShow primed on the test data private HSLFSlideShow hssA; private HSLFSlideShow hssB; + private HSLFSlideShow hssC; // POIFS primed on the test data private POIFSFileSystem pfsA; private POIFSFileSystem pfsB; + private POIFSFileSystem pfsC; public void setUp() throws Exception { String dirname = System.getProperty("HSLF.testdata.path"); @@ -53,6 +55,11 @@ public class TestReWrite extends TestCase { FileInputStream fisB = new FileInputStream(filenameB); pfsB = new POIFSFileSystem(fisB); hssB = new HSLFSlideShow(pfsB); + + String filenameC = dirname + "/WithMacros.ppt"; + FileInputStream fisC = new FileInputStream(filenameC); + pfsC = new POIFSFileSystem(fisC); + hssC = new HSLFSlideShow(pfsC); } public void testWritesOutTheSame() throws Exception { @@ -85,6 +92,34 @@ public class TestReWrite extends TestCase { assertEquals(_oData[i], _nData[i]); } } + + public void testWithMacroStreams() throws Exception { + // Check that they're apparently the same + assertSlideShowWritesOutTheSame(hssC, pfsC); + + // Currently has a Macros stream + assertNotNull( pfsC.getRoot().getEntry("Macros") ); + + // Write out normally, will loose the macro stream + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + hssC.write(baos); + POIFSFileSystem pfsNew = new POIFSFileSystem( + new ByteArrayInputStream(baos.toByteArray()) ); + + try { + pfsNew.getRoot().getEntry("Macros"); + fail(); + } catch(FileNotFoundException e) { + // Good, as expected + } + + // But if we write out with nodes preserved, will be there + baos = new ByteArrayOutputStream(); + hssC.write(baos, true); + pfsNew = new POIFSFileSystem( + new ByteArrayInputStream(baos.toByteArray()) ); + assertNotNull( pfsNew.getRoot().getEntry("Macros") ); + } /** * Ensure that simply opening a slideshow (usermodel) view of it diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/WithMacros.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/WithMacros.ppt new file mode 100644 index 0000000000000000000000000000000000000000..1c722315313c41b31785185adde972d9e2ed5b00 GIT binary patch literal 16896 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 literal 0 HcmV?d00001