diff --git a/build.xml b/build.xml index ce1cf7ff4..4dac62c70 100644 --- a/build.xml +++ b/build.xml @@ -387,6 +387,10 @@ under the License. + + diff --git a/src/java/org/apache/poi/POIDocument.java b/src/java/org/apache/poi/POIDocument.java new file mode 100644 index 000000000..bc3b78dd2 --- /dev/null +++ b/src/java/org/apache/poi/POIDocument.java @@ -0,0 +1,216 @@ +/* ==================================================================== + 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; + +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; + +/** + * This holds the common functionality for all POI + * Document classes. + * Currently, this relates to Document Information Properties + * + * @author Nick Burch + */ +public abstract class POIDocument { + /** Holds metadata on our document */ + protected SummaryInformation sInf; + /** Holds further metadata on our document */ + protected DocumentSummaryInformation dsInf; + /** The open POIFS FileSystem that contains our document */ + protected POIFSFileSystem filesystem; + + /** For our own logging use */ + protected POILogger logger = POILogFactory.getLogger(this.getClass()); + + + /** + * Fetch the Document Summary Information of the document + */ + public DocumentSummaryInformation getDocumentSummaryInformation() { return dsInf; } + + /** + * Fetch the Summary Information of the document + */ + public SummaryInformation getSummaryInformation() { return sInf; } + + /** + * Find, and create objects for, the standard + * Documment Information Properties (HPSF) + */ + protected void readProperties() { + // DocumentSummaryInformation + dsInf = (DocumentSummaryInformation)getPropertySet(DocumentSummaryInformation.DEFAULT_STREAM_NAME); + + // SummaryInformation + sInf = (SummaryInformation)getPropertySet(SummaryInformation.DEFAULT_STREAM_NAME); + } + + /** + * For a given named property entry, either return it or null if + * if it wasn't found + */ + protected PropertySet getPropertySet(String setName) { + DocumentInputStream dis; + try { + // Find the entry, and get an input stream for it + dis = filesystem.createDocumentInputStream(setName); + } catch(IOException ie) { + // Oh well, doesn't exist + System.err.println("Error getting property set with name " + setName + "\n" + ie); + return null; + } + + try { + // Create the Property Set + PropertySet set = PropertySetFactory.create(dis); + return set; + } catch(IOException ie) { + // Must be corrupt or something like that + System.err.println("Error creating property set with name " + setName + "\n" + ie); + } catch(org.apache.poi.hpsf.HPSFException he) { + // Oh well, doesn't exist + System.err.println("Error creating property set with name " + setName + "\n" + he); + } + return null; + } + + /** + * Writes out the standard Documment Information Properties (HPSF) + * @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); + } + } + } + + /** + * Writes out a given ProperySet + * @param name the (POIFS Level) name of the property to write + * @param set the PropertySet to write out + * @param outFS the POIFSFileSystem to write the property into + */ + protected void writePropertySet(String name, PropertySet set, POIFSFileSystem outFS) throws IOException { + try { + MutablePropertySet mSet = new MutablePropertySet(set); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + mSet.write(bOut); + byte[] data = bOut.toByteArray(); + ByteArrayInputStream bIn = new ByteArrayInputStream(data); + outFS.createDocument(bIn,name); + + logger.log(POILogger.INFO, "Wrote property set " + name + " of size " + data.length); + } catch(org.apache.poi.hpsf.WritingNotSupportedException wnse) { + 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/testcases/org/apache/poi/TestPOIDocument.java b/src/testcases/org/apache/poi/TestPOIDocument.java new file mode 100644 index 000000000..3b80aba7d --- /dev/null +++ b/src/testcases/org/apache/poi/TestPOIDocument.java @@ -0,0 +1,117 @@ + +/* ==================================================================== + 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; + + +import junit.framework.TestCase; +import java.io.*; + +import org.apache.poi.hslf.HSLFSlideShow; +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.poifs.filesystem.*; + +/** + * Tests that POIDocument correctly loads and saves the common + * (hspf) Document Properties + * + * @author Nick Burch (nick at torchbox dot com) + */ +public class TestPOIDocument extends TestCase { + // The POI Documents to work on + private POIDocument doc; + private POIDocument doc2; + // POIFS primed on the test (powerpoint and word) data + private POIFSFileSystem pfs; + private POIFSFileSystem pfs2; + + /** + * Set things up, using a PowerPoint document and + * a Word Document for our testing + */ + public void setUp() throws Exception { + String dirnameHSLF = System.getProperty("HSLF.testdata.path"); + String filenameHSLF = dirnameHSLF + "/basic_test_ppt_file.ppt"; + String dirnameHWPF = System.getProperty("HWPF.testdata.path"); + String filenameHWPF = dirnameHWPF + "/test2.doc"; + + FileInputStream fisHSLF = new FileInputStream(filenameHSLF); + pfs = new POIFSFileSystem(fisHSLF); + doc = new HSLFSlideShow(pfs); + + FileInputStream fisHWPF = new FileInputStream(filenameHWPF); + pfs2 = new POIFSFileSystem(fisHWPF); + doc2 = new HWPFDocument(pfs2); + } + + public void testReadProperties() throws Exception { + // We should have both sets + assertNotNull(doc.getDocumentSummaryInformation()); + assertNotNull(doc.getSummaryInformation()); + + // Check they are as expected for the test doc + assertEquals("Hogwarts", doc.getSummaryInformation().getAuthor()); + assertEquals(10598, doc.getDocumentSummaryInformation().getByteCount()); + } + + public void testReadProperties2() throws Exception { + // Check again on the word one + assertNotNull(doc2.getDocumentSummaryInformation()); + assertNotNull(doc2.getSummaryInformation()); + + assertEquals("Hogwarts", doc2.getSummaryInformation().getAuthor()); + assertEquals("", doc2.getSummaryInformation().getKeywords()); + assertEquals(0, doc2.getDocumentSummaryInformation().getByteCount()); + } + + public void testWriteProperties() throws Exception { + // Just check we can write them back out into a filesystem + POIFSFileSystem outFS = new POIFSFileSystem(); + doc.writeProperties(outFS); + + // Should now hold them + assertNotNull( + outFS.createDocumentInputStream("\005SummaryInformation") + ); + assertNotNull( + outFS.createDocumentInputStream("\005DocumentSummaryInformation") + ); + } + + public void testWriteReadProperties() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // Write them out + POIFSFileSystem outFS = new POIFSFileSystem(); + doc.writeProperties(outFS); + outFS.writeFilesystem(baos); + + // Create a new version + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + POIFSFileSystem inFS = new POIFSFileSystem(bais); + + // Check they're still there + doc.filesystem = inFS; + doc.readProperties(); + + // Delegate test + testReadProperties(); + } +} diff --git a/src/testcases/org/apache/poi/hslf/data/basic_test_ppt_file.ppt b/src/testcases/org/apache/poi/hslf/data/basic_test_ppt_file.ppt new file mode 100644 index 000000000..af16393f4 Binary files /dev/null and b/src/testcases/org/apache/poi/hslf/data/basic_test_ppt_file.ppt differ diff --git a/src/testcases/org/apache/poi/hwpf/data/test2.doc b/src/testcases/org/apache/poi/hwpf/data/test2.doc new file mode 100755 index 000000000..06921df39 Binary files /dev/null and b/src/testcases/org/apache/poi/hwpf/data/test2.doc differ