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 000000000..1c7223153 Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/WithMacros.ppt differ