2007-09-19 07:56:36 -04:00
|
|
|
/* ====================================================================
|
|
|
|
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;
|
2008-05-20 13:12:08 -04:00
|
|
|
import java.io.OutputStream;
|
2007-09-19 07:56:36 -04:00
|
|
|
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;
|
2008-04-10 12:59:10 -04:00
|
|
|
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
2007-09-19 07:56:36 -04:00
|
|
|
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 */
|
2009-08-20 09:49:33 -04:00
|
|
|
private SummaryInformation sInf;
|
2007-09-19 07:56:36 -04:00
|
|
|
/** Holds further metadata on our document */
|
2009-08-20 09:49:33 -04:00
|
|
|
private DocumentSummaryInformation dsInf;
|
2007-09-19 07:56:36 -04:00
|
|
|
/** The open POIFS FileSystem that contains our document */
|
|
|
|
protected POIFSFileSystem filesystem;
|
2008-04-10 12:59:10 -04:00
|
|
|
/** The directory that our document lives in */
|
|
|
|
protected DirectoryNode directory;
|
2007-09-19 07:56:36 -04:00
|
|
|
|
|
|
|
/** For our own logging use */
|
2009-08-20 09:49:33 -04:00
|
|
|
private final static POILogger logger = POILogFactory.getLogger(POIDocument.class);
|
2007-09-19 07:56:36 -04:00
|
|
|
|
2008-03-03 10:10:46 -05:00
|
|
|
/* Have the property streams been read yet? (Only done on-demand) */
|
2009-08-20 09:49:33 -04:00
|
|
|
private boolean initialized = false;
|
2008-04-10 12:59:10 -04:00
|
|
|
|
|
|
|
|
|
|
|
protected POIDocument(DirectoryNode dir, POIFSFileSystem fs) {
|
|
|
|
this.filesystem = fs;
|
|
|
|
this.directory = dir;
|
|
|
|
}
|
|
|
|
protected POIDocument(POIFSFileSystem fs) {
|
|
|
|
this(fs.getRoot(), fs);
|
|
|
|
}
|
2008-03-03 10:10:46 -05:00
|
|
|
|
|
|
|
/**
|
2007-09-19 07:56:36 -04:00
|
|
|
* Fetch the Document Summary Information of the document
|
|
|
|
*/
|
2008-03-03 10:10:46 -05:00
|
|
|
public DocumentSummaryInformation getDocumentSummaryInformation() {
|
|
|
|
if(!initialized) readProperties();
|
|
|
|
return dsInf;
|
|
|
|
}
|
2007-09-19 07:56:36 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch the Summary Information of the document
|
|
|
|
*/
|
2008-03-03 10:10:46 -05:00
|
|
|
public SummaryInformation getSummaryInformation() {
|
|
|
|
if(!initialized) readProperties();
|
|
|
|
return sInf;
|
|
|
|
}
|
2009-11-25 07:37:48 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Will create whichever of SummaryInformation
|
|
|
|
* and DocumentSummaryInformation (HPSF) properties
|
|
|
|
* are not already part of your document.
|
|
|
|
* This is normally useful when creating a new
|
|
|
|
* document from scratch.
|
|
|
|
* If the information properties are already there,
|
|
|
|
* then nothing will happen.
|
|
|
|
*/
|
|
|
|
public void createInformationProperties() {
|
|
|
|
if(!initialized) readProperties();
|
|
|
|
if(sInf == null) {
|
|
|
|
sInf = PropertySetFactory.newSummaryInformation();
|
|
|
|
}
|
|
|
|
if(dsInf == null) {
|
|
|
|
dsInf = PropertySetFactory.newDocumentSummaryInformation();
|
|
|
|
}
|
|
|
|
}
|
2007-09-19 07:56:36 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Find, and create objects for, the standard
|
2008-02-11 14:14:04 -05:00
|
|
|
* Documment Information Properties (HPSF).
|
|
|
|
* If a given property set is missing or corrupt,
|
|
|
|
* it will remain null;
|
2007-09-19 07:56:36 -04:00
|
|
|
*/
|
|
|
|
protected void readProperties() {
|
2008-02-11 14:14:04 -05:00
|
|
|
PropertySet ps;
|
|
|
|
|
2007-09-19 07:56:36 -04:00
|
|
|
// DocumentSummaryInformation
|
2008-02-11 14:14:04 -05:00
|
|
|
ps = getPropertySet(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
|
|
|
if(ps != null && ps instanceof DocumentSummaryInformation) {
|
|
|
|
dsInf = (DocumentSummaryInformation)ps;
|
|
|
|
} else if(ps != null) {
|
|
|
|
logger.log(POILogger.WARN, "DocumentSummaryInformation property set came back with wrong class - ", ps.getClass());
|
|
|
|
}
|
2007-09-19 07:56:36 -04:00
|
|
|
|
|
|
|
// SummaryInformation
|
2008-02-11 14:14:04 -05:00
|
|
|
ps = getPropertySet(SummaryInformation.DEFAULT_STREAM_NAME);
|
|
|
|
if(ps instanceof SummaryInformation) {
|
|
|
|
sInf = (SummaryInformation)ps;
|
|
|
|
} else if(ps != null) {
|
|
|
|
logger.log(POILogger.WARN, "SummaryInformation property set came back with wrong class - ", ps.getClass());
|
|
|
|
}
|
2008-03-03 10:10:46 -05:00
|
|
|
|
|
|
|
// Mark the fact that we've now loaded up the properties
|
|
|
|
initialized = true;
|
2007-09-19 07:56:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For a given named property entry, either return it or null if
|
|
|
|
* if it wasn't found
|
|
|
|
*/
|
|
|
|
protected PropertySet getPropertySet(String setName) {
|
2009-08-20 09:49:33 -04:00
|
|
|
//directory can be null when creating new documents
|
|
|
|
if(directory == null) return null;
|
|
|
|
|
|
|
|
DocumentInputStream dis;
|
2007-09-19 07:56:36 -04:00
|
|
|
try {
|
|
|
|
// Find the entry, and get an input stream for it
|
2008-04-10 12:59:10 -04:00
|
|
|
dis = directory.createDocumentInputStream(setName);
|
2007-09-19 07:56:36 -04:00
|
|
|
} catch(IOException ie) {
|
|
|
|
// Oh well, doesn't exist
|
2007-09-19 10:40:44 -04:00
|
|
|
logger.log(POILogger.WARN, "Error getting property set with name " + setName + "\n" + ie);
|
2007-09-19 07:56:36 -04:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Create the Property Set
|
|
|
|
PropertySet set = PropertySetFactory.create(dis);
|
|
|
|
return set;
|
|
|
|
} catch(IOException ie) {
|
|
|
|
// Must be corrupt or something like that
|
2007-09-19 10:40:44 -04:00
|
|
|
logger.log(POILogger.WARN, "Error creating property set with name " + setName + "\n" + ie);
|
2007-09-19 07:56:36 -04:00
|
|
|
} catch(org.apache.poi.hpsf.HPSFException he) {
|
|
|
|
// Oh well, doesn't exist
|
2007-09-19 10:40:44 -04:00
|
|
|
logger.log(POILogger.WARN, "Error creating property set with name " + setName + "\n" + he);
|
2007-09-19 07:56:36 -04:00
|
|
|
}
|
|
|
|
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 {
|
2009-08-20 09:49:33 -04:00
|
|
|
SummaryInformation si = getSummaryInformation();
|
|
|
|
if(si != null) {
|
|
|
|
writePropertySet(SummaryInformation.DEFAULT_STREAM_NAME, si, outFS);
|
2007-09-19 07:56:36 -04:00
|
|
|
if(writtenEntries != null) {
|
|
|
|
writtenEntries.add(SummaryInformation.DEFAULT_STREAM_NAME);
|
|
|
|
}
|
|
|
|
}
|
2009-08-20 09:49:33 -04:00
|
|
|
DocumentSummaryInformation dsi = getDocumentSummaryInformation();
|
|
|
|
if(dsi != null) {
|
|
|
|
writePropertySet(DocumentSummaryInformation.DEFAULT_STREAM_NAME, dsi, outFS);
|
2007-09-19 07:56:36 -04:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
2008-05-20 13:12:08 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes the document out to the specified output stream
|
|
|
|
*/
|
|
|
|
public abstract void write(OutputStream out) throws IOException;
|
2007-09-19 07:56:36 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|