#62649 - Remove OPOIFS

Fix HPSF UTF-8 encoding error with Bug52311.doc while refactoring CopyCompare/EntryUtils

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1839201 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2018-08-26 11:55:00 +00:00
parent 63d904acb2
commit e4bd5e838f
74 changed files with 1771 additions and 5721 deletions

View File

@ -20,8 +20,6 @@ package org.apache.poi.hpsf.examples;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -30,19 +28,21 @@ import java.io.UnsupportedEncodingException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.HPSFRuntimeException; import org.apache.poi.hpsf.HPSFRuntimeException;
import org.apache.poi.hpsf.MarkUnsupportedException; import org.apache.poi.hpsf.MarkUnsupportedException;
import org.apache.poi.hpsf.NoPropertySetStreamException; import org.apache.poi.hpsf.NoPropertySetStreamException;
import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.PropertySetFactory;
import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
import org.apache.poi.hpsf.WritingNotSupportedException; import org.apache.poi.hpsf.WritingNotSupportedException;
import org.apache.poi.poifs.eventfilesystem.POIFSReader; import org.apache.poi.poifs.eventfilesystem.POIFSReader;
import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
import org.apache.poi.poifs.filesystem.DirectoryEntry; 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.DocumentInputStream;
import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.EntryUtils;
import org.apache.poi.poifs.filesystem.POIFSDocumentPath; import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;
@ -66,36 +66,27 @@ import org.apache.poi.util.TempFile;
* with the same attributes, and the sections must contain the same properties. * with the same attributes, and the sections must contain the same properties.
* Details like the ordering of the properties do not matter.</p> * Details like the ordering of the properties do not matter.</p>
*/ */
public class CopyCompare { public final class CopyCompare {
private CopyCompare() {}
/** /**
* <p>Runs the example program. The application expects one or two * Runs the example program. The application expects one or two arguments:
* arguments:</p> *
* <p>
* <ol> * <ol>
* <p> * <li>The first argument is the disk file name of the POI filesystem to copy.</li>
* <li><p>The first argument is the disk file name of the POI filesystem to * <li>The second argument is optional. If it is given, it is the name of
* copy.</p></li>
* <p>
* <li><p>The second argument is optional. If it is given, it is the name of
* a disk file the copy of the POI filesystem will be written to. If it is * a disk file the copy of the POI filesystem will be written to. If it is
* not given, the copy will be written to a temporary file which will be * not given, the copy will be written to a temporary file which will be
* deleted at the end of the program.</p></li> * deleted at the end of the program.</li>
* <p>
* </ol> * </ol>
* *
* @param args Command-line arguments. * @param args Command-line arguments.
* @throws MarkUnsupportedException if a POI document stream does not
* support the mark() operation.
* @throws NoPropertySetStreamException if the application tries to
* create a property set from a POI document stream that is not a property
* set stream.
* @throws IOException if any I/O exception occurs. * @throws IOException if any I/O exception occurs.
* @throws UnsupportedEncodingException if a character encoding is not * @throws UnsupportedEncodingException if a character encoding is not
* supported. * supported.
*/ */
public static void main(final String[] args) public static void main(final String[] args)
throws NoPropertySetStreamException, MarkUnsupportedException, throws UnsupportedEncodingException, IOException {
UnsupportedEncodingException, IOException {
String originalFileName = null; String originalFileName = null;
String copyFileName = null; String copyFileName = null;
@ -120,10 +111,9 @@ public class CopyCompare {
final CopyFile cf = new CopyFile(copyFileName); final CopyFile cf = new CopyFile(copyFileName);
r.registerListener(cf); r.registerListener(cf);
r.setNotifyEmptyDirectories(true); r.setNotifyEmptyDirectories(true);
try (FileInputStream fis = new FileInputStream(originalFileName)) {
r.read(fis); r.read(new File(originalFileName));
}
/* Write the new POIFS to disk. */ /* Write the new POIFS to disk. */
cf.close(); cf.close();
@ -133,124 +123,10 @@ public class CopyCompare {
POIFSFileSystem cpfs = new POIFSFileSystem(new File(copyFileName))) { POIFSFileSystem cpfs = new POIFSFileSystem(new File(copyFileName))) {
final DirectoryEntry oRoot = opfs.getRoot(); final DirectoryEntry oRoot = opfs.getRoot();
final DirectoryEntry cRoot = cpfs.getRoot(); final DirectoryEntry cRoot = cpfs.getRoot();
final StringBuffer messages = new StringBuffer(); System.out.println(EntryUtils.areDirectoriesIdentical(oRoot, cRoot) ? "Equal" : "Not equal");
if (equal(oRoot, cRoot, messages)) {
System.out.println("Equal");
} else {
System.out.println("Not equal: " + messages);
}
} }
} }
/**
* <p>Compares two {@link DirectoryEntry} instances of a POI file system.
* The directories must contain the same streams with the same names and
* contents.</p>
*
* @param d1 The first directory.
* @param d2 The second directory.
* @param msg The method may append human-readable comparison messages to
* this string buffer.
* @return <code>true</code> if the directories are equal, else
* <code>false</code>.
* @throws MarkUnsupportedException if a POI document stream does not
* support the mark() operation.
* @throws NoPropertySetStreamException if the application tries to
* create a property set from a POI document stream that is not a property
* set stream.
* @throws IOException if any I/O exception occurs.
*/
private static boolean equal(final DirectoryEntry d1,
final DirectoryEntry d2,
final StringBuffer msg)
throws NoPropertySetStreamException, MarkUnsupportedException,
UnsupportedEncodingException, IOException {
boolean equal = true;
/* Iterate over d1 and compare each entry with its counterpart in d2. */
for (final Entry e1 : d1) {
final String n1 = e1.getName();
if (!d2.hasEntry(n1)) {
msg.append("Document \"").append(n1).append("\" exists only in the source.\n");
equal = false;
break;
}
Entry e2 = d2.getEntry(n1);
if (e1.isDirectoryEntry() && e2.isDirectoryEntry()) {
equal = equal((DirectoryEntry) e1, (DirectoryEntry) e2, msg);
} else if (e1.isDocumentEntry() && e2.isDocumentEntry()) {
equal = equal((DocumentEntry) e1, (DocumentEntry) e2, msg);
} else {
msg.append("One of \"").append(e1).append("\" and \"").append(e2).append("\" is a ").append("document while the other one is a directory.\n");
equal = false;
}
}
/* Iterate over d2 just to make sure that there are no entries in d2
* that are not in d1. */
for (final Entry e2 : d2) {
final String n2 = e2.getName();
Entry e1 = null;
try {
e1 = d1.getEntry(n2);
} catch (FileNotFoundException ex) {
msg.append("Document \"").append(e2).append("\" exitsts, document \"").append(e1).append("\" does not.\n");
equal = false;
break;
}
}
return equal;
}
/**
* <p>Compares two {@link DocumentEntry} instances of a POI file system.
* Documents that are not property set streams must be bitwise identical.
* Property set streams must be logically equal.</p>
*
* @param d1 The first document.
* @param d2 The second document.
* @param msg The method may append human-readable comparison messages to
* this string buffer.
* @return <code>true</code> if the documents are equal, else
* <code>false</code>.
* @throws MarkUnsupportedException if a POI document stream does not
* support the mark() operation.
* @throws NoPropertySetStreamException if the application tries to
* create a property set from a POI document stream that is not a property
* set stream.
* @throws IOException if any I/O exception occurs.
*/
private static boolean equal(final DocumentEntry d1, final DocumentEntry d2,
final StringBuffer msg)
throws NoPropertySetStreamException, MarkUnsupportedException,
UnsupportedEncodingException, IOException {
try (DocumentInputStream dis1 = new DocumentInputStream(d1); DocumentInputStream dis2 = new DocumentInputStream(d2)) {
if (PropertySet.isPropertySetStream(dis1) &&
PropertySet.isPropertySetStream(dis2)) {
final PropertySet ps1 = PropertySetFactory.create(dis1);
final PropertySet ps2 = PropertySetFactory.create(dis2);
if (!ps1.equals(ps2)) {
msg.append("Property sets are not equal.\n");
return false;
}
} else {
int i1, i2;
do {
i1 = dis1.read();
i2 = dis2.read();
if (i1 != i2) {
msg.append("Documents are not equal.\n");
return false;
}
} while (i1 > -1);
}
}
return true;
}
/** /**
* <p>This class does all the work. Its method {@link * <p>This class does all the work. Its method {@link
* #processPOIFSReaderEvent(POIFSReaderEvent)} is called for each file in * #processPOIFSReaderEvent(POIFSReaderEvent)} is called for each file in
@ -274,7 +150,7 @@ public class CopyCompare {
* @param dstName The name of the disk file the destination POIFS is to * @param dstName The name of the disk file the destination POIFS is to
* be written to. * be written to.
*/ */
public CopyFile(final String dstName) { CopyFile(final String dstName) {
this.dstName = dstName; this.dstName = dstName;
poiFs = new POIFSFileSystem(); poiFs = new POIFSFileSystem();
} }
@ -332,7 +208,7 @@ public class CopyCompare {
/** /**
* <p>Writes a {@link PropertySet} to a POI filesystem.</p> * Writes a {@link PropertySet} to a POI filesystem.
* *
* @param poiFs The POI filesystem to write to. * @param poiFs The POI filesystem to write to.
* @param path The file's path in the POI filesystem. * @param path The file's path in the POI filesystem.
@ -345,14 +221,25 @@ public class CopyCompare {
final PropertySet ps) final PropertySet ps)
throws WritingNotSupportedException, IOException { throws WritingNotSupportedException, IOException {
final DirectoryEntry de = getPath(poiFs, path); final DirectoryEntry de = getPath(poiFs, path);
final PropertySet mps = new PropertySet(ps); final PropertySet mps;
try {
if (ps instanceof DocumentSummaryInformation) {
mps = new DocumentSummaryInformation(ps);
} else if (ps instanceof SummaryInformation) {
mps = new SummaryInformation(ps);
} else {
mps = new PropertySet(ps);
}
} catch (UnexpectedPropertySetTypeException e) {
throw new IOException(e);
}
de.createDocument(name, mps.toInputStream()); de.createDocument(name, mps.toInputStream());
} }
/** /**
* <p>Copies the bytes from a {@link DocumentInputStream} to a new * Copies the bytes from a {@link DocumentInputStream} to a new
* stream in a POI filesystem.</p> * stream in a POI filesystem.
* *
* @param poiFs The POI filesystem to write to. * @param poiFs The POI filesystem to write to.
* @param path The source document's path. * @param path The source document's path.
@ -385,9 +272,9 @@ public class CopyCompare {
/** /**
* <p>Writes the POI file system to a disk file.</p> * Writes the POI file system to a disk file.
*/ */
public void close() throws FileNotFoundException, IOException { public void close() throws IOException {
out = new FileOutputStream(dstName); out = new FileOutputStream(dstName);
poiFs.writeFilesystem(out); poiFs.writeFilesystem(out);
out.close(); out.close();
@ -456,11 +343,7 @@ public class CopyCompare {
/* This exception will be thrown if the directory already /* This exception will be thrown if the directory already
* exists. However, since we have full control about directory * exists. However, since we have full control about directory
* creation we can ensure that this will never happen. */ * creation we can ensure that this will never happen. */
ex.printStackTrace(System.err); throw new RuntimeException(ex);
throw new RuntimeException(ex.toString());
/* FIXME (2): Replace the previous line by the following once we
* no longer need JDK 1.3 compatibility. */
// throw new RuntimeException(ex);
} }
} }
} }

View File

@ -17,7 +17,7 @@
package org.apache.poi.hpsf.examples; package org.apache.poi.hpsf.examples;
import java.io.FileInputStream; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -37,8 +37,9 @@ import org.apache.poi.util.HexDump;
* *
* <p>Explanations can be found in the HPSF HOW-TO.</p> * <p>Explanations can be found in the HPSF HOW-TO.</p>
*/ */
public class ReadCustomPropertySets public final class ReadCustomPropertySets {
{
private ReadCustomPropertySets() {}
/** /**
* <p>Runs the example program.</p> * <p>Runs the example program.</p>
@ -54,7 +55,7 @@ public class ReadCustomPropertySets
/* Register a listener for *all* documents. */ /* Register a listener for *all* documents. */
r.registerListener(new MyPOIFSReaderListener()); r.registerListener(new MyPOIFSReaderListener());
r.read(new FileInputStream(filename)); r.read(new File(filename));
} }
@ -117,12 +118,12 @@ public class ReadCustomPropertySets
} }
} }
static void out(final String msg) private static void out(final String msg)
{ {
System.out.println(msg); System.out.println(msg);
} }
static String hex(final byte[] bytes) private static String hex(final byte[] bytes)
{ {
return HexDump.dump(bytes, 0L, 0); return HexDump.dump(bytes, 0L, 0);
} }

View File

@ -17,7 +17,7 @@
package org.apache.poi.hpsf.examples; package org.apache.poi.hpsf.examples;
import java.io.FileInputStream; import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.PropertySetFactory;
@ -33,8 +33,10 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
* *
* <p>Explanations can be found in the HPSF HOW-TO.</p> * <p>Explanations can be found in the HPSF HOW-TO.</p>
*/ */
public class ReadTitle public final class ReadTitle
{ {
private ReadTitle() {}
/** /**
* <p>Runs the example program.</p> * <p>Runs the example program.</p>
* *
@ -47,7 +49,7 @@ public class ReadTitle
final String filename = args[0]; final String filename = args[0];
POIFSReader r = new POIFSReader(); POIFSReader r = new POIFSReader();
r.registerListener(new MyPOIFSReaderListener(), SummaryInformation.DEFAULT_STREAM_NAME); r.registerListener(new MyPOIFSReaderListener(), SummaryInformation.DEFAULT_STREAM_NAME);
r.read(new FileInputStream(filename)); r.read(new File(filename));
} }

View File

@ -19,8 +19,7 @@ package org.apache.poi.hpsf.examples;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.FileInputStream; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -28,7 +27,15 @@ import java.io.OutputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.poi.hpsf.*; import org.apache.poi.hpsf.HPSFRuntimeException;
import org.apache.poi.hpsf.MarkUnsupportedException;
import org.apache.poi.hpsf.NoPropertySetStreamException;
import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.PropertySetFactory;
import org.apache.poi.hpsf.Section;
import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.hpsf.Variant;
import org.apache.poi.hpsf.WritingNotSupportedException;
import org.apache.poi.hpsf.wellknown.PropertyIDMap; import org.apache.poi.hpsf.wellknown.PropertyIDMap;
import org.apache.poi.poifs.eventfilesystem.POIFSReader; import org.apache.poi.poifs.eventfilesystem.POIFSReader;
import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
@ -72,8 +79,9 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
* *
* <p>Further explanations can be found in the HPSF HOW-TO.</p> * <p>Further explanations can be found in the HPSF HOW-TO.</p>
*/ */
public class WriteAuthorAndTitle public final class WriteAuthorAndTitle {
{ private WriteAuthorAndTitle() {}
/** /**
* <p>Runs the example program.</p> * <p>Runs the example program.</p>
* *
@ -101,10 +109,8 @@ public class WriteAuthorAndTitle
final POIFSReader r = new POIFSReader(); final POIFSReader r = new POIFSReader();
final ModifySICopyTheRest msrl = new ModifySICopyTheRest(dstName); final ModifySICopyTheRest msrl = new ModifySICopyTheRest(dstName);
r.registerListener(msrl); r.registerListener(msrl);
FileInputStream fis = new FileInputStream(srcName); r.read(new File(srcName));
r.read(fis);
fis.close();
/* Write the new POIFS to disk. */ /* Write the new POIFS to disk. */
msrl.close(); msrl.close();
} }
@ -127,14 +133,14 @@ public class WriteAuthorAndTitle
/** /**
* <p>The constructor of a {@link ModifySICopyTheRest} instance creates * The constructor of a {@link ModifySICopyTheRest} instance creates
* the target POIFS. It also stores the name of the file the POIFS will * the target POIFS. It also stores the name of the file the POIFS will
* be written to once it is complete.</p> * be written to once it is complete.
* *
* @param dstName The name of the disk file the destination POIFS is to * @param dstName The name of the disk file the destination POIFS is to
* be written to. * be written to.
*/ */
public ModifySICopyTheRest(final String dstName) ModifySICopyTheRest(final String dstName)
{ {
this.dstName = dstName; this.dstName = dstName;
poiFs = new POIFSFileSystem(); poiFs = new POIFSFileSystem();
@ -142,8 +148,8 @@ public class WriteAuthorAndTitle
/** /**
* <p>The method is called by POI's eventing API for each file in the * The method is called by POI's eventing API for each file in the
* origin POIFS.</p> * origin POIFS.
*/ */
@Override @Override
public void processPOIFSReaderEvent(final POIFSReaderEvent event) public void processPOIFSReaderEvent(final POIFSReaderEvent event)
@ -213,7 +219,7 @@ public class WriteAuthorAndTitle
* @param si The property set. It should be a summary information * @param si The property set. It should be a summary information
* property set. * property set.
*/ */
public void editSI(final POIFSFileSystem poiFs, void editSI(final POIFSFileSystem poiFs,
final POIFSDocumentPath path, final POIFSDocumentPath path,
final String name, final String name,
final PropertySet si) final PropertySet si)
@ -297,9 +303,9 @@ public class WriteAuthorAndTitle
/** /**
* <p>Writes the POI file system to a disk file.</p> * Writes the POI file system to a disk file.
*/ */
public void close() throws FileNotFoundException, IOException public void close() throws IOException
{ {
out = new FileOutputStream(dstName); out = new FileOutputStream(dstName);
poiFs.writeFilesystem(out); poiFs.writeFilesystem(out);

View File

@ -19,7 +19,7 @@ package org.apache.poi.poifs.poibrowser;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.io.FileInputStream; import java.io.File;
import java.io.IOException; import java.io.IOException;
import javax.swing.JFrame; import javax.swing.JFrame;
@ -42,12 +42,6 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReader;
public class POIBrowser extends JFrame public class POIBrowser extends JFrame
{ {
/**
* <p>The tree's root node must be visible to all methods.</p>
*/
protected MutableTreeNode rootNode;
/** /**
* <p>Takes a bunch of file names as command line parameters, * <p>Takes a bunch of file names as command line parameters,
@ -59,8 +53,6 @@ public class POIBrowser extends JFrame
new POIBrowser().run(args); new POIBrowser().run(args);
} }
protected void run(String[] args) protected void run(String[] args)
{ {
addWindowListener(new WindowAdapter() addWindowListener(new WindowAdapter()
@ -74,8 +66,11 @@ public class POIBrowser extends JFrame
/* Create the tree model with a root node. The latter is /* Create the tree model with a root node. The latter is
* invisible but it must be present because a tree model * invisible but it must be present because a tree model
* always needs a root. */ * always needs a root.
rootNode = new DefaultMutableTreeNode("POI Filesystems"); *
* The tree's root node must be visible to all methods.
*/
MutableTreeNode rootNode = new DefaultMutableTreeNode("POI Filesystems");
DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
/* Create the tree UI element. */ /* Create the tree UI element. */
@ -85,10 +80,10 @@ public class POIBrowser extends JFrame
/* Add the POI filesystems to the tree. */ /* Add the POI filesystems to the tree. */
int displayedFiles = 0; int displayedFiles = 0;
for (final String filename : args) { for (final String filename : args) {
try (FileInputStream fis = new FileInputStream(filename)) { try {
POIFSReader r = new POIFSReader(); POIFSReader r = new POIFSReader();
r.registerListener(new TreeReaderListener(filename, rootNode)); r.registerListener(new TreeReaderListener(filename, rootNode));
r.read(fis); r.read(new File(filename));
displayedFiles++; displayedFiles++;
} catch (IOException ex) { } catch (IOException ex) {
System.err.println(filename + ": " + ex); System.err.println(filename + ": " + ex);

View File

@ -40,7 +40,6 @@ import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptor;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentInputStream; import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
@ -75,14 +74,6 @@ public abstract class POIDocument implements Closeable {
this.directory = dir; this.directory = dir;
} }
/**
* Constructs from an old-style OPOIFS
*
* @param fs the filesystem the document is read from
*/
protected POIDocument(OPOIFSFileSystem fs) {
this(fs.getRoot());
}
/** /**
* Constructs from an old-style OPOIFS * Constructs from an old-style OPOIFS
* *
@ -195,6 +186,7 @@ public abstract class POIDocument implements Closeable {
* @param setName The property to read * @param setName The property to read
* @return The value of the given property or null if it wasn't found. * @return The value of the given property or null if it wasn't found.
*/ */
@SuppressWarnings("WeakerAccess")
protected PropertySet getPropertySet(String setName) throws IOException { protected PropertySet getPropertySet(String setName) throws IOException {
return getPropertySet(setName, getEncryptionInfo()); return getPropertySet(setName, getEncryptionInfo());
} }
@ -207,6 +199,7 @@ public abstract class POIDocument implements Closeable {
* @param encryptionInfo the encryption descriptor in case of cryptoAPI encryption * @param encryptionInfo the encryption descriptor in case of cryptoAPI encryption
* @return The value of the given property or null if it wasn't found. * @return The value of the given property or null if it wasn't found.
*/ */
@SuppressWarnings("WeakerAccess")
protected PropertySet getPropertySet(String setName, EncryptionInfo encryptionInfo) throws IOException { protected PropertySet getPropertySet(String setName, EncryptionInfo encryptionInfo) throws IOException {
DirectoryNode dirNode = directory; DirectoryNode dirNode = directory;
@ -329,7 +322,7 @@ public abstract class POIDocument implements Closeable {
* @throws IOException if an error when writing to the * @throws IOException if an error when writing to the
* {@link NPOIFSFileSystem} occurs * {@link NPOIFSFileSystem} occurs
*/ */
protected void writePropertySet(String name, PropertySet set, NPOIFSFileSystem outFS) throws IOException { private void writePropertySet(String name, PropertySet set, NPOIFSFileSystem outFS) throws IOException {
try { try {
PropertySet mSet = new PropertySet(set); PropertySet mSet = new PropertySet(set);
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ByteArrayOutputStream bOut = new ByteArrayOutputStream();
@ -420,8 +413,9 @@ public abstract class POIDocument implements Closeable {
/** /**
* Closes the underlying {@link NPOIFSFileSystem} from which * Closes the underlying {@link NPOIFSFileSystem} from which
* the document was read, if any. Has no effect on documents * the document was read, if any. Has no effect on documents
* opened from an InputStream, or newly created ones. * opened from an InputStream, or newly created ones.<p>
* <p>Once close() has been called, no further operations *
* Once {@code close()} has been called, no further operations
* should be called on the document. * should be called on the document.
*/ */
@Override @Override
@ -468,13 +462,10 @@ public abstract class POIDocument implements Closeable {
* to a new POIFSFileSystem * to a new POIFSFileSystem
* *
* @param newDirectory the new directory * @param newDirectory the new directory
* @return the old/previous directory
*/ */
@Internal @Internal
protected DirectoryNode replaceDirectory(DirectoryNode newDirectory) { protected void replaceDirectory(DirectoryNode newDirectory) {
DirectoryNode dn = directory;
directory = newDirectory; directory = newDirectory;
return dn;
} }
/** /**

View File

@ -21,8 +21,6 @@ import java.io.OutputStream;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/** /**
@ -32,16 +30,10 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
* @since POI 3.15 beta 3 * @since POI 3.15 beta 3
*/ */
public abstract class POIReadOnlyDocument extends POIDocument { public abstract class POIReadOnlyDocument extends POIDocument {
public POIReadOnlyDocument(DirectoryNode dir) { protected POIReadOnlyDocument(DirectoryNode dir) {
super(dir); super(dir);
} }
public POIReadOnlyDocument(NPOIFSFileSystem fs) { protected POIReadOnlyDocument(NPOIFSFileSystem fs) {
super(fs);
}
public POIReadOnlyDocument(OPOIFSFileSystem fs) {
super(fs);
}
public POIReadOnlyDocument(POIFSFileSystem fs) {
super(fs); super(fs);
} }

View File

@ -26,20 +26,14 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.OldExcelFormatException; import org.apache.poi.hssf.OldExcelFormatException;
import org.apache.poi.hssf.extractor.EventBasedExcelExtractor; import org.apache.poi.hssf.extractor.EventBasedExcelExtractor;
import org.apache.poi.hssf.extractor.ExcelExtractor; import org.apache.poi.hssf.extractor.ExcelExtractor;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -50,24 +44,24 @@ import org.apache.poi.util.POILogger;
* <p>Note 1 - will fail for many file formats if the POI Scratchpad jar is * <p>Note 1 - will fail for many file formats if the POI Scratchpad jar is
* not present on the runtime classpath</p> * not present on the runtime classpath</p>
* <p>Note 2 - for text extractor creation across all formats, use * <p>Note 2 - for text extractor creation across all formats, use
* {@link org.apache.poi.extractor.ExtractorFactory} contained within * {@link org.apache.poi.ooxml.extractor.ExtractorFactory} contained within
* the OOXML jar.</p> * the OOXML jar.</p>
* <p>Note 3 - rather than using this, for most cases you would be better * <p>Note 3 - rather than using this, for most cases you would be better
* off switching to <a href="http://tika.apache.org">Apache Tika</a> instead!</p> * off switching to <a href="http://tika.apache.org">Apache Tika</a> instead!</p>
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public class OLE2ExtractorFactory { public final class OLE2ExtractorFactory {
private static final POILogger LOGGER = POILogFactory.getLogger(OLE2ExtractorFactory.class); private static final POILogger LOGGER = POILogFactory.getLogger(OLE2ExtractorFactory.class);
/** Should this thread prefer event based over usermodel based extractors? */ /** Should this thread prefer event based over usermodel based extractors? */
private static final ThreadLocal<Boolean> threadPreferEventExtractors = new ThreadLocal<Boolean>() { private static final ThreadLocal<Boolean> threadPreferEventExtractors = ThreadLocal.withInitial(() -> Boolean.FALSE);
@Override
protected Boolean initialValue() { return Boolean.FALSE; }
};
/** Should all threads prefer event based over usermodel based extractors? */ /** Should all threads prefer event based over usermodel based extractors? */
private static Boolean allPreferEventExtractors; private static Boolean allPreferEventExtractors;
private OLE2ExtractorFactory() {
}
/** /**
* Should this thread prefer event based over usermodel based extractors? * Should this thread prefer event based over usermodel based extractors?
* (usermodel extractors tend to be more accurate, but use more memory) * (usermodel extractors tend to be more accurate, but use more memory)
@ -113,16 +107,16 @@ public class OLE2ExtractorFactory {
return threadPreferEventExtractors.get(); return threadPreferEventExtractors.get();
} }
@SuppressWarnings("unchecked")
public static <T extends POITextExtractor> T createExtractor(POIFSFileSystem fs) throws IOException { public static <T extends POITextExtractor> T createExtractor(POIFSFileSystem fs) throws IOException {
return (T)createExtractor(fs.getRoot()); return (T)createExtractor(fs.getRoot());
} }
@SuppressWarnings("unchecked")
public static <T extends POITextExtractor> T createExtractor(NPOIFSFileSystem fs) throws IOException { public static <T extends POITextExtractor> T createExtractor(NPOIFSFileSystem fs) throws IOException {
return (T)createExtractor(fs.getRoot()); return (T)createExtractor(fs.getRoot());
} }
public static <T extends POITextExtractor> T createExtractor(OPOIFSFileSystem fs) throws IOException {
return (T)createExtractor(fs.getRoot());
}
@SuppressWarnings("unchecked")
public static <T extends POITextExtractor> T createExtractor(InputStream input) throws IOException { public static <T extends POITextExtractor> T createExtractor(InputStream input) throws IOException {
Class<?> cls = getOOXMLClass(); Class<?> cls = getOOXMLClass();
if (cls != null) { if (cls != null) {
@ -165,7 +159,7 @@ public class OLE2ExtractorFactory {
/** /**
* Create the Extractor, if possible. Generally needs the Scratchpad jar. * Create the Extractor, if possible. Generally needs the Scratchpad jar.
* Note that this won't check for embedded OOXML resources either, use * Note that this won't check for embedded OOXML resources either, use
* {@link org.apache.poi.extractor.ExtractorFactory} for that. * {@link org.apache.poi.ooxml.extractor.ExtractorFactory} for that.
*/ */
public static POITextExtractor createExtractor(DirectoryNode poifsDir) throws IOException { public static POITextExtractor createExtractor(DirectoryNode poifsDir) throws IOException {
// Look for certain entries in the stream, to figure it // Look for certain entries in the stream, to figure it
@ -205,6 +199,7 @@ public class OLE2ExtractorFactory {
* empty array. Otherwise, you'll get one open * empty array. Otherwise, you'll get one open
* {@link POITextExtractor} for each embedded file. * {@link POITextExtractor} for each embedded file.
*/ */
@SuppressWarnings("unused")
public static POITextExtractor[] getEmbededDocsTextExtractors(POIOLE2TextExtractor ext) public static POITextExtractor[] getEmbededDocsTextExtractors(POIOLE2TextExtractor ext)
throws IOException throws IOException
{ {
@ -254,40 +249,11 @@ public class OLE2ExtractorFactory {
for (InputStream nonPOIF : nonPOIFS) { for (InputStream nonPOIF : nonPOIFS) {
try { try {
e.add(createExtractor(nonPOIF)); e.add(createExtractor(nonPOIF));
} catch (IllegalArgumentException ie) {
// Ignore, just means it didn't contain
// a format we support as yet
LOGGER.log(POILogger.WARN, ie);
} catch (Exception xe) { } catch (Exception xe) {
// Ignore, invalid format // Ignore, invalid format
LOGGER.log(POILogger.WARN, xe); LOGGER.log(POILogger.WARN, xe);
} }
} }
return e.toArray(new POITextExtractor[e.size()]); return e.toArray(new POITextExtractor[0]);
}
private static POITextExtractor createEncyptedOOXMLExtractor(DirectoryNode poifsDir)
throws IOException {
String pass = Biff8EncryptionKey.getCurrentUserPassword();
if (pass == null) {
pass = Decryptor.DEFAULT_PASSWORD;
}
EncryptionInfo ei = new EncryptionInfo(poifsDir);
Decryptor dec = ei.getDecryptor();
InputStream is = null;
try {
if (!dec.verifyPassword(pass)) {
throw new EncryptedDocumentException("Invalid password specified - use Biff8EncryptionKey.setCurrentUserPassword() before calling extractor");
}
is = dec.getDataStream(poifsDir);
return createExtractor(is);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
} finally {
IOUtils.closeQuietly(is);
}
} }
} }

View File

@ -26,7 +26,6 @@ import org.apache.poi.POIDocument;
import org.apache.poi.poifs.filesystem.EntryUtils; import org.apache.poi.poifs.filesystem.EntryUtils;
import org.apache.poi.poifs.filesystem.FilteringDirectoryNode; import org.apache.poi.poifs.filesystem.FilteringDirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/** /**
@ -39,9 +38,6 @@ public class HPSFPropertiesOnlyDocument extends POIDocument {
public HPSFPropertiesOnlyDocument(NPOIFSFileSystem fs) { public HPSFPropertiesOnlyDocument(NPOIFSFileSystem fs) {
super(fs.getRoot()); super(fs.getRoot());
} }
public HPSFPropertiesOnlyDocument(OPOIFSFileSystem fs) {
super(fs);
}
public HPSFPropertiesOnlyDocument(POIFSFileSystem fs) { public HPSFPropertiesOnlyDocument(POIFSFileSystem fs) {
super(fs); super(fs);
} }
@ -60,24 +56,18 @@ public class HPSFPropertiesOnlyDocument extends POIDocument {
* Write out, with any properties changes, but nothing else * Write out, with any properties changes, but nothing else
*/ */
public void write(File newFile) throws IOException { public void write(File newFile) throws IOException {
POIFSFileSystem fs = POIFSFileSystem.create(newFile); try (POIFSFileSystem fs = POIFSFileSystem.create(newFile)) {
try {
write(fs); write(fs);
fs.writeFilesystem(); fs.writeFilesystem();
} finally {
fs.close();
} }
} }
/** /**
* Write out, with any properties changes, but nothing else * Write out, with any properties changes, but nothing else
*/ */
public void write(OutputStream out) throws IOException { public void write(OutputStream out) throws IOException {
NPOIFSFileSystem fs = new NPOIFSFileSystem(); try (NPOIFSFileSystem fs = new NPOIFSFileSystem()) {
try {
write(fs); write(fs);
fs.writeFilesystem(out); fs.writeFilesystem(out);
} finally {
fs.close();
} }
} }

View File

@ -345,9 +345,13 @@ public class Property {
* @return the truncated size with a maximum of 4 bytes shorter (3 bytes + trailing 0 of strings) * @return the truncated size with a maximum of 4 bytes shorter (3 bytes + trailing 0 of strings)
*/ */
private static int unpaddedLength(byte[] buf) { private static int unpaddedLength(byte[] buf) {
int len; final int end = (buf.length-(buf.length+3)%4);
for (len = buf.length; len > 0 && len > buf.length-4 && buf[len-1] == 0; len--); for (int i = buf.length; i>end; i--) {
return len; if (buf[i-1] != 0) {
return i;
}
}
return end;
} }

View File

@ -34,8 +34,11 @@ import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutputStream;
import org.apache.poi.util.NotImplemented; import org.apache.poi.util.NotImplemented;
import org.apache.poi.util.Removal;
/** /**
* Represents a property set in the Horrible Property Set Format * Represents a property set in the Horrible Property Set Format
@ -175,8 +178,6 @@ public class PropertySet {
* *
* @param stream Holds the data making out the property set * @param stream Holds the data making out the property set
* stream. * stream.
* @throws MarkUnsupportedException
* if the stream does not support the {@link InputStream#markSupported} method.
* @throws IOException * @throws IOException
* if the {@link InputStream} cannot be accessed as needed. * if the {@link InputStream} cannot be accessed as needed.
* @exception NoPropertySetStreamException * @exception NoPropertySetStreamException
@ -185,8 +186,7 @@ public class PropertySet {
* if a character encoding is not supported. * if a character encoding is not supported.
*/ */
public PropertySet(final InputStream stream) public PropertySet(final InputStream stream)
throws NoPropertySetStreamException, MarkUnsupportedException, throws NoPropertySetStreamException, IOException {
IOException, UnsupportedEncodingException {
if (!isPropertySetStream(stream)) { if (!isPropertySetStream(stream)) {
throw new NoPropertySetStreamException(); throw new NoPropertySetStreamException();
} }
@ -266,6 +266,7 @@ public class PropertySet {
* *
* @param byteOrder The property set stream's low-level "byte order" field. * @param byteOrder The property set stream's low-level "byte order" field.
*/ */
@SuppressWarnings("WeakerAccess")
public void setByteOrder(int byteOrder) { public void setByteOrder(int byteOrder) {
this.byteOrder = byteOrder; this.byteOrder = byteOrder;
} }
@ -298,6 +299,7 @@ public class PropertySet {
* *
* @param osVersion The property set stream's low-level "OS version" field. * @param osVersion The property set stream's low-level "OS version" field.
*/ */
@SuppressWarnings("WeakerAccess")
public void setOSVersion(int osVersion) { public void setOSVersion(int osVersion) {
this.osVersion = osVersion; this.osVersion = osVersion;
} }
@ -315,6 +317,7 @@ public class PropertySet {
* *
* @param classID The property set stream's low-level "class ID" field. * @param classID The property set stream's low-level "class ID" field.
*/ */
@SuppressWarnings("WeakerAccess")
public void setClassID(ClassID classID) { public void setClassID(ClassID classID) {
this.classID = classID; this.classID = classID;
} }
@ -374,12 +377,10 @@ public class PropertySet {
* {@link InputStream#mark} method. * {@link InputStream#mark} method.
* @return {@code true} if the stream is a property set * @return {@code true} if the stream is a property set
* stream, else {@code false}. * stream, else {@code false}.
* @throws MarkUnsupportedException if the {@link InputStream}
* does not support the {@link InputStream#mark} method.
* @exception IOException if an I/O error occurs * @exception IOException if an I/O error occurs
*/ */
public static boolean isPropertySetStream(final InputStream stream) public static boolean isPropertySetStream(final InputStream stream)
throws MarkUnsupportedException, IOException { throws IOException {
/* /*
* Read at most this many bytes. * Read at most this many bytes.
*/ */
@ -408,30 +409,34 @@ public class PropertySet {
* @return {@code true} if the byte array is a property set * @return {@code true} if the byte array is a property set
* stream, {@code false} if not. * stream, {@code false} if not.
*/ */
@SuppressWarnings({"unused", "WeakerAccess"})
public static boolean isPropertySetStream(final byte[] src, final int offset, final int length) { public static boolean isPropertySetStream(final byte[] src, final int offset, final int length) {
/* FIXME (3): Ensure that at most "length" bytes are read. */ LittleEndianByteArrayInputStream leis = new LittleEndianByteArrayInputStream(src, offset, length);
/* /*
* Read the header fields of the stream. They must always be * Read the header fields of the stream. They must always be
* there. * there.
*/ */
int o = offset; try {
final int byteOrder = LittleEndian.getUShort(src, o); final int byteOrder = leis.readUShort();
o += LittleEndianConsts.SHORT_SIZE; if (byteOrder != BYTE_ORDER_ASSERTION) {
if (byteOrder != BYTE_ORDER_ASSERTION) { return false;
}
final int format = leis.readUShort();
if (format != FORMAT_ASSERTION) {
return false;
}
final long osVersion = leis.readUInt();
byte[] clsBuf = new byte[ClassID.LENGTH];
leis.readFully(clsBuf);
final ClassID classID = new ClassID(clsBuf, 0);
final long sectionCount = leis.readUInt();
return (sectionCount >= 0);
} catch (RuntimeException e) {
return false; return false;
} }
final int format = LittleEndian.getUShort(src, o);
o += LittleEndianConsts.SHORT_SIZE;
if (format != FORMAT_ASSERTION) {
return false;
}
// final long osVersion = LittleEndian.getUInt(src, offset);
o += LittleEndianConsts.INT_SIZE;
// final ClassID classID = new ClassID(src, offset);
o += ClassID.LENGTH;
final long sectionCount = LittleEndian.getUInt(src, o);
return (sectionCount >= 0);
} }
@ -452,7 +457,7 @@ public class PropertySet {
private void init(final byte[] src, final int offset, final int length) private void init(final byte[] src, final int offset, final int length)
throws UnsupportedEncodingException { throws UnsupportedEncodingException {
/* FIXME (3): Ensure that at most "length" bytes are read. */ /* FIXME (3): Ensure that at most "length" bytes are read. */
/* /*
* Read the stream's header fields. * Read the stream's header fields.
*/ */
@ -504,50 +509,60 @@ public class PropertySet {
* @exception WritingNotSupportedException if HPSF does not yet support * @exception WritingNotSupportedException if HPSF does not yet support
* writing a property's variant type. * writing a property's variant type.
*/ */
public void write(final OutputStream out) public void write(final OutputStream out) throws IOException, WritingNotSupportedException {
throws WritingNotSupportedException, IOException {
out.write(toBytes());
/* Indicate that we're done */
out.close();
}
private byte[] toBytes() throws WritingNotSupportedException, IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);
/* Write the number of sections in this property set stream. */ /* Write the number of sections in this property set stream. */
final int nrSections = getSectionCount(); final int nrSections = getSectionCount();
/* Write the property set's header. */ /* Write the property set's header. */
LittleEndian.putShort(out, (short) getByteOrder()); leos.writeShort(getByteOrder());
LittleEndian.putShort(out, (short) getFormat()); leos.writeShort(getFormat());
LittleEndian.putInt(getOSVersion(), out); leos.writeInt(getOSVersion());
putClassId(out, getClassID()); putClassId(bos, getClassID());
LittleEndian.putInt(nrSections, out); leos.writeInt(nrSections);
int offset = OFFSET_HEADER;
assert(bos.size() == OFFSET_HEADER);
final int[][] offsets = new int[getSectionCount()][2];
/* Write the section list, i.e. the references to the sections. Each /* Write the section list, i.e. the references to the sections. Each
* entry in the section list consist of the section's class ID and the * entry in the section list consist of the section's class ID and the
* section's offset relative to the beginning of the stream. */ * section's offset relative to the beginning of the stream. */
offset += nrSections * (ClassID.LENGTH + LittleEndianConsts.INT_SIZE); int secCnt = 0;
final int sectionsBegin = offset;
for (final Section section : getSections()) { for (final Section section : getSections()) {
final ClassID formatID = section.getFormatID(); final ClassID formatID = section.getFormatID();
if (formatID == null) { if (formatID == null) {
throw new NoFormatIDException(); throw new NoFormatIDException();
} }
putClassId(out, formatID); putClassId(bos, formatID);
LittleEndian.putUInt(offset, out); offsets[secCnt++][0] = bos.size();
try { // offset dummy - filled later
offset += section.getSize(); leos.writeInt(-1);
} catch (HPSFRuntimeException ex) {
final Throwable cause = ex.getReason();
if (cause instanceof UnsupportedEncodingException) {
throw new IllegalPropertySetDataException(cause);
}
throw ex;
}
} }
/* Write the sections themselves. */ /* Write the sections themselves. */
offset = sectionsBegin; secCnt = 0;
for (final Section section : getSections()) { for (final Section section : getSections()) {
offset += section.write(out); offsets[secCnt++][1] = bos.size();
section.write(bos);
} }
/* Indicate that we're done */ byte[] result = bos.toByteArray();
out.close(); for (int[] off : offsets) {
LittleEndian.putInt(result, off[0], off[1]);
}
return result;
} }
/** /**
@ -586,15 +601,8 @@ public class PropertySet {
* of a property's variant type. * of a property's variant type.
* @throws IOException if an I/O exception occurs. * @throws IOException if an I/O exception occurs.
*/ */
public InputStream toInputStream() throws IOException, WritingNotSupportedException { public InputStream toInputStream() throws WritingNotSupportedException, IOException {
final ByteArrayOutputStream psStream = new ByteArrayOutputStream(); return new ByteArrayInputStream(toBytes());
try {
write(psStream);
} finally {
psStream.close();
}
final byte[] streamData = psStream.toByteArray();
return new ByteArrayInputStream(streamData);
} }
/** /**
@ -605,7 +613,7 @@ public class PropertySet {
* *
* @return The property as a String, or null if unavailable * @return The property as a String, or null if unavailable
*/ */
protected String getPropertyStringValue(final int propertyId) { String getPropertyStringValue(final int propertyId) {
Object propertyValue = getProperty(propertyId); Object propertyValue = getProperty(propertyId);
return getPropertyStringValue(propertyValue); return getPropertyStringValue(propertyValue);
} }
@ -724,7 +732,7 @@ public class PropertySet {
* @throws NoSingleSectionException if the {@link PropertySet} has * @throws NoSingleSectionException if the {@link PropertySet} has
* more or less than one {@link Section}. * more or less than one {@link Section}.
*/ */
protected boolean getPropertyBooleanValue(final int id) throws NoSingleSectionException { boolean getPropertyBooleanValue(final int id) throws NoSingleSectionException {
return getFirstSection().getPropertyBooleanValue(id); return getFirstSection().getPropertyBooleanValue(id);
} }
@ -742,7 +750,7 @@ public class PropertySet {
* @throws NoSingleSectionException if the {@link PropertySet} has * @throws NoSingleSectionException if the {@link PropertySet} has
* more or less than one {@link Section}. * more or less than one {@link Section}.
*/ */
protected int getPropertyIntValue(final int id) throws NoSingleSectionException { int getPropertyIntValue(final int id) throws NoSingleSectionException {
return getFirstSection().getPropertyIntValue(id); return getFirstSection().getPropertyIntValue(id);
} }
@ -774,6 +782,7 @@ public class PropertySet {
* *
* @return The {@link PropertySet}'s first section. * @return The {@link PropertySet}'s first section.
*/ */
@SuppressWarnings("WeakerAccess")
public Section getFirstSection() { public Section getFirstSection() {
if (sections.isEmpty()) { if (sections.isEmpty()) {
throw new MissingSectionException("Property set does not contain any sections."); throw new MissingSectionException("Property set does not contain any sections.");
@ -787,7 +796,11 @@ public class PropertySet {
* If the {@link PropertySet} has only a single section this method returns it. * If the {@link PropertySet} has only a single section this method returns it.
* *
* @return The singleSection value * @return The singleSection value
*
* @deprecated superfluous convenience method
*/ */
@Deprecated
@Removal(version="5.0.0")
public Section getSingleSection() { public Section getSingleSection() {
final int sectionCount = getSectionCount(); final int sectionCount = getSectionCount();
if (sectionCount != 1) { if (sectionCount != 1) {
@ -809,7 +822,7 @@ public class PropertySet {
*/ */
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
if (o == null || !(o instanceof PropertySet)) { if (!(o instanceof PropertySet)) {
return false; return false;
} }
final PropertySet ps = (PropertySet) o; final PropertySet ps = (PropertySet) o;
@ -877,27 +890,28 @@ public class PropertySet {
} }
protected void remove1stProperty(long id) { void remove1stProperty(long id) {
getFirstSection().removeProperty(id); getFirstSection().removeProperty(id);
} }
protected void set1stProperty(long id, String value) { void set1stProperty(long id, String value) {
getFirstSection().setProperty((int)id, value); getFirstSection().setProperty((int)id, value);
} }
protected void set1stProperty(long id, int value) { void set1stProperty(long id, int value) {
getFirstSection().setProperty((int)id, value); getFirstSection().setProperty((int)id, value);
} }
protected void set1stProperty(long id, boolean value) { void set1stProperty(long id, boolean value) {
getFirstSection().setProperty((int)id, value); getFirstSection().setProperty((int)id, value);
} }
protected void set1stProperty(long id, byte[] value) { @SuppressWarnings("SameParameterValue")
void set1stProperty(long id, byte[] value) {
getFirstSection().setProperty((int)id, value); getFirstSection().setProperty((int)id, value);
} }
private static void putClassId(final OutputStream out, final ClassID n) throws IOException { private static void putClassId(final ByteArrayOutputStream out, final ClassID n) {
byte[] b = new byte[16]; byte[] b = new byte[16];
n.write(b, 0); n.write(b, 0);
out.write(b, 0, b.length); out.write(b, 0, b.length);

View File

@ -36,6 +36,7 @@ import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutputStream;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -81,7 +82,7 @@ public class Section {
* #getPropertyIntValue} or {@link #getProperty} tried to access a * #getPropertyIntValue} or {@link #getProperty} tried to access a
* property that was not available, else {@code false}. * property that was not available, else {@code false}.
*/ */
private boolean wasNull; private transient boolean wasNull;
/** /**
* Creates an empty {@link Section}. * Creates an empty {@link Section}.
@ -292,6 +293,7 @@ public class Section {
* @param formatID The section's format ID as a byte array. It components * @param formatID The section's format ID as a byte array. It components
* are in big-endian format. * are in big-endian format.
*/ */
@SuppressWarnings("WeakerAccess")
public void setFormatID(final byte[] formatID) { public void setFormatID(final byte[] formatID) {
ClassID fid = getFormatID(); ClassID fid = getFormatID();
if (fid == null) { if (fid == null) {
@ -325,7 +327,7 @@ public class Section {
* @return This section's properties. * @return This section's properties.
*/ */
public Property[] getProperties() { public Property[] getProperties() {
return properties.values().toArray(new Property[properties.size()]); return properties.values().toArray(new Property[0]);
} }
/** /**
@ -375,7 +377,7 @@ public class Section {
* @see #getProperty * @see #getProperty
*/ */
public void setProperty(final int id, final int value) { public void setProperty(final int id, final int value) {
setProperty(id, Variant.VT_I4, Integer.valueOf(value)); setProperty(id, Variant.VT_I4, value);
} }
@ -390,7 +392,7 @@ public class Section {
* @see #getProperty * @see #getProperty
*/ */
public void setProperty(final int id, final long value) { public void setProperty(final int id, final long value) {
setProperty(id, Variant.VT_I8, Long.valueOf(value)); setProperty(id, Variant.VT_I8, value);
} }
@ -405,7 +407,7 @@ public class Section {
* @see #getProperty * @see #getProperty
*/ */
public void setProperty(final int id, final boolean value) { public void setProperty(final int id, final boolean value) {
setProperty(id, Variant.VT_BOOL, Boolean.valueOf(value)); setProperty(id, Variant.VT_BOOL, value);
} }
@ -487,7 +489,7 @@ public class Section {
* *
* @return The property's value * @return The property's value
*/ */
protected int getPropertyIntValue(final long id) { int getPropertyIntValue(final long id) {
final Number i; final Number i;
final Object o = getProperty(id); final Object o = getProperty(id);
if (o == null) { if (o == null) {
@ -513,9 +515,9 @@ public class Section {
* *
* @return The property's value * @return The property's value
*/ */
protected boolean getPropertyBooleanValue(final int id) { boolean getPropertyBooleanValue(final int id) {
final Boolean b = (Boolean) getProperty(id); final Boolean b = (Boolean) getProperty(id);
return b != null && b.booleanValue(); return b != null && b;
} }
/** /**
@ -529,8 +531,9 @@ public class Section {
* @see #getProperty * @see #getProperty
* @see Variant * @see Variant
*/ */
@SuppressWarnings("unused")
protected void setPropertyBooleanValue(final int id, final boolean value) { protected void setPropertyBooleanValue(final int id, final boolean value) {
setProperty(id, Variant.VT_BOOL, Boolean.valueOf(value)); setProperty(id, Variant.VT_BOOL, value);
} }
/** /**
@ -588,6 +591,7 @@ public class Section {
* #getPropertyIntValue} or {@link #getProperty} tried to access a * #getPropertyIntValue} or {@link #getProperty} tried to access a
* property that was not available, else {@code false}. * property that was not available, else {@code false}.
*/ */
@SuppressWarnings("WeakerAccess")
public boolean wasNull() { public boolean wasNull() {
return wasNull; return wasNull;
} }
@ -674,7 +678,7 @@ public class Section {
for (Long id : propIds) { for (Long id : propIds) {
Property p1 = properties.get(id); Property p1 = properties.get(id);
Property p2 = s.properties.get(id); Property p2 = s.properties.get(id);
if (p1 == null || p2 == null || !p1.equals(p2)) { if (p1 == null || !p1.equals(p2)) {
return false; return false;
} }
} }
@ -683,7 +687,7 @@ public class Section {
Map<Long,String> d1 = getDictionary(); Map<Long,String> d1 = getDictionary();
Map<Long,String> d2 = s.getDictionary(); Map<Long,String> d2 = s.getDictionary();
return (d1 == null && d2 == null) || (d1 != null && d2 != null && d1.equals(d2)); return (d1 == null && d2 == null) || (d1 != null && d1.equals(d2));
} }
/** /**
@ -691,6 +695,7 @@ public class Section {
* *
* @param id The ID of the property to be removed * @param id The ID of the property to be removed
*/ */
@SuppressWarnings("WeakerAccess")
public void removeProperty(final long id) { public void removeProperty(final long id) {
if (properties.remove(id) != null) { if (properties.remove(id) != null) {
sectionBytes.reset(); sectionBytes.reset();
@ -731,60 +736,54 @@ public class Section {
codepage = Property.DEFAULT_CODEPAGE; codepage = Property.DEFAULT_CODEPAGE;
} }
/* The properties are written to this stream. */ final int[][] offsets = new int[properties.size()][2];
final ByteArrayOutputStream propertyStream = new ByteArrayOutputStream(); final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);
/* The property list is established here. After each property that has /* Write the section's length - dummy value, fixed later */
* been written to "propertyStream", a property list entry is written to leos.writeInt(-1);
* "propertyListStream". */
final ByteArrayOutputStream propertyListStream = new ByteArrayOutputStream();
/* Maintain the current position in the list. */ /* Write the section's number of properties: */
int position = 0; leos.writeInt(properties.size());
int propCnt = 0;
for (Property p : properties.values()) {
/* Write the property list entry. */
leos.writeUInt(p.getID());
// dummy offset to be fixed later
offsets[propCnt++][0] = bos.size();
leos.writeInt(-1);
}
/* Increase the position variable by the size of the property list so
* that it points behind the property list and to the beginning of the
* properties themselves. */
position += 2 * LittleEndianConsts.INT_SIZE + getPropertyCount() * 2 * LittleEndianConsts.INT_SIZE;
/* Write the properties and the property list into their respective /* Write the properties and the property list into their respective
* streams: */ * streams: */
propCnt = 0;
for (Property p : properties.values()) { for (Property p : properties.values()) {
final long id = p.getID(); offsets[propCnt++][1] = bos.size();
/* Write the property list entry. */
LittleEndian.putUInt(id, propertyListStream);
LittleEndian.putUInt(position, propertyListStream);
/* If the property ID is not equal 0 we write the property and all /* If the property ID is not equal 0 we write the property and all
* is fine. However, if it equals 0 we have to write the section's * is fine. However, if it equals 0 we have to write the section's
* dictionary which has an implicit type only and an explicit * dictionary which has an implicit type only and an explicit
* value. */ * value. */
if (id != 0) { if (p.getID() != 0) {
/* Write the property and update the position to the next /* Write the property and update the position to the next
* property. */ * property. */
position += p.write(propertyStream, codepage); p.write(bos, codepage);
} else { } else {
position += writeDictionary(propertyStream, codepage); writeDictionary(bos, codepage);
} }
} }
/* Write the section: */ byte[] result = bos.toByteArray();
int streamLength = LittleEndianConsts.INT_SIZE * 2 + propertyListStream.size() + propertyStream.size(); LittleEndian.putInt(result, 0, bos.size());
/* Write the section's length: */ for (int[] off : offsets) {
LittleEndian.putInt(streamLength, out); LittleEndian.putUInt(result, off[0], off[1]);
}
/* Write the section's number of properties: */ out.write(result);
LittleEndian.putInt(getPropertyCount(), out);
/* Write the property list: */ return bos.size();
propertyListStream.writeTo(out);
/* Write the properties: */
propertyStream.writeTo(out);
return streamLength;
} }
/** /**
@ -795,12 +794,8 @@ public class Section {
* @param codepage The codepage of the string values. * @param codepage The codepage of the string values.
* *
* @return {@code true} if dictionary was read successful, {@code false} otherwise * @return {@code true} if dictionary was read successful, {@code false} otherwise
*
* @throws UnsupportedEncodingException if the dictionary's codepage is not
* (yet) supported.
*/ */
private boolean readDictionary(LittleEndianByteArrayInputStream leis, final int length, final int codepage) private boolean readDictionary(LittleEndianByteArrayInputStream leis, final int length, final int codepage) {
throws UnsupportedEncodingException {
Map<Long,String> dic = new HashMap<>(); Map<Long,String> dic = new HashMap<>();
/* /*
@ -863,13 +858,12 @@ public class Section {
* *
* @param out The output stream to write to. * @param out The output stream to write to.
* @param codepage The codepage to be used to write the dictionary items. * @param codepage The codepage to be used to write the dictionary items.
* @return The number of bytes written
* @exception IOException if an I/O exception occurs. * @exception IOException if an I/O exception occurs.
*/ */
private int writeDictionary(final OutputStream out, final int codepage) private void writeDictionary(final OutputStream out, final int codepage)
throws IOException { throws IOException {
final byte padding[] = new byte[4]; final byte padding[] = new byte[4];
Map<Long,String> dic = getDictionary(); final Map<Long,String> dic = getDictionary();
LittleEndian.putUInt(dic.size(), out); LittleEndian.putUInt(dic.size(), out);
int length = LittleEndianConsts.INT_SIZE; int length = LittleEndianConsts.INT_SIZE;
@ -878,26 +872,23 @@ public class Section {
LittleEndian.putUInt(ls.getKey(), out); LittleEndian.putUInt(ls.getKey(), out);
length += LittleEndianConsts.INT_SIZE; length += LittleEndianConsts.INT_SIZE;
String value = ls.getValue()+"\0"; final String value = ls.getValue()+"\0";
LittleEndian.putUInt( value.length(), out ); final byte bytes[] = CodePageUtil.getBytesInCodePage(value, codepage);
final int len = (codepage == CodePageUtil.CP_UNICODE) ? value.length() : bytes.length;
LittleEndian.putUInt( len, out );
length += LittleEndianConsts.INT_SIZE; length += LittleEndianConsts.INT_SIZE;
byte bytes[] = CodePageUtil.getBytesInCodePage(value, codepage);
out.write(bytes); out.write(bytes);
length += bytes.length; length += bytes.length;
if (codepage == CodePageUtil.CP_UNICODE) { final int pad = (codepage == CodePageUtil.CP_UNICODE) ? ((4 - (length & 0x3)) & 0x3) : 0;
int pad = (4 - (length & 0x3)) & 0x3; out.write(padding, 0, pad);
out.write(padding, 0, pad); length += pad;
length += pad;
}
} }
int pad = (4 - (length & 0x3)) & 0x3; final int pad = (4 - (length & 0x3)) & 0x3;
out.write(padding, 0, pad); out.write(padding, 0, pad);
length += pad;
return length;
} }
/** /**

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -15,27 +14,8 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.poifs.storage;
import java.util.*;
/** /**
* A list of SmallDocumentBlocks instances, and methods to manage the list * common package contains constants and other classes shared across all POIFS subpackages
*/ */
public class SmallDocumentBlockList package org.apache.poi.poifs.common;
extends BlockListImpl
{
/**
* Constructor SmallDocumentBlockList
*
* @param blocks a list of SmallDocumentBlock instances
*/
public SmallDocumentBlockList(final List<SmallDocumentBlock> blocks)
{
setBlocks(blocks.toArray(new SmallDocumentBlock[blocks.size()]));
}
}

View File

@ -27,7 +27,6 @@ import javax.crypto.spec.SecretKeySpec;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public abstract class Decryptor implements Cloneable { public abstract class Decryptor implements Cloneable {
@ -87,7 +86,7 @@ public abstract class Decryptor implements Cloneable {
* @param cipher may be null, otherwise the given instance is reset to the new block index * @param cipher may be null, otherwise the given instance is reset to the new block index
* @param block the block index, e.g. the persist/slide id (hslf) * @param block the block index, e.g. the persist/slide id (hslf)
* @return a new cipher object, if cipher was null, otherwise the reinitialized cipher * @return a new cipher object, if cipher was null, otherwise the reinitialized cipher
* @throws GeneralSecurityException * @throws GeneralSecurityException if the cipher can't be initialized
*/ */
public Cipher initCipherForBlock(Cipher cipher, int block) public Cipher initCipherForBlock(Cipher cipher, int block)
throws GeneralSecurityException { throws GeneralSecurityException {
@ -126,10 +125,6 @@ public abstract class Decryptor implements Cloneable {
return getDataStream(fs.getRoot()); return getDataStream(fs.getRoot());
} }
public InputStream getDataStream(OPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}
public InputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException { public InputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot()); return getDataStream(fs.getRoot());
} }
@ -147,6 +142,7 @@ public abstract class Decryptor implements Cloneable {
return integrityHmacKey; return integrityHmacKey;
} }
@SuppressWarnings("unused")
public byte[] getIntegrityHmacValue() { public byte[] getIntegrityHmacValue() {
return integrityHmacValue; return integrityHmacValue;
} }
@ -167,6 +163,7 @@ public abstract class Decryptor implements Cloneable {
this.integrityHmacValue = (integrityHmacValue == null) ? null : integrityHmacValue.clone(); this.integrityHmacValue = (integrityHmacValue == null) ? null : integrityHmacValue.clone();
} }
@SuppressWarnings("unused")
protected int getBlockSizeInBytes() { protected int getBlockSizeInBytes() {
return encryptionInfo.getHeader().getBlockSize(); return encryptionInfo.getHeader().getBlockSize();
} }

View File

@ -27,7 +27,6 @@ import java.io.IOException;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
@ -59,12 +58,14 @@ public class EncryptionInfo implements Cloneable {
* A value that MUST be 0 if document properties are encrypted. * A value that MUST be 0 if document properties are encrypted.
* The encryption of document properties is specified in section 2.3.5.4. * The encryption of document properties is specified in section 2.3.5.4.
*/ */
@SuppressWarnings("WeakerAccess")
public static final BitField flagDocProps = BitFieldFactory.getInstance(0x08); public static final BitField flagDocProps = BitFieldFactory.getInstance(0x08);
/** /**
* A value that MUST be 1 if extensible encryption is used. If this value is 1, * A value that MUST be 1 if extensible encryption is used. If this value is 1,
* the value of every other field in this structure MUST be 0. * the value of every other field in this structure MUST be 0.
*/ */
@SuppressWarnings("WeakerAccess")
public static final BitField flagExternal = BitFieldFactory.getInstance(0x10); public static final BitField flagExternal = BitFieldFactory.getInstance(0x10);
/** /**
@ -81,13 +82,6 @@ public class EncryptionInfo implements Cloneable {
this(fs.getRoot()); this(fs.getRoot());
} }
/**
* Opens for decryption
*/
public EncryptionInfo(OPOIFSFileSystem fs) throws IOException {
this(fs.getRoot());
}
/** /**
* Opens for decryption * Opens for decryption
*/ */
@ -167,11 +161,11 @@ public class EncryptionInfo implements Cloneable {
* *
* @param encryptionMode see {@link EncryptionMode} for values, {@link EncryptionMode#cryptoAPI} is for * @param encryptionMode see {@link EncryptionMode} for values, {@link EncryptionMode#cryptoAPI} is for
* internal use only, as it's record based * internal use only, as it's record based
* @param cipherAlgorithm * @param cipherAlgorithm the cipher algorithm
* @param hashAlgorithm * @param hashAlgorithm the hash algorithm
* @param keyBits * @param keyBits the bit count of the key
* @param blockSize * @param blockSize the size of a cipher block
* @param chainingMode * @param chainingMode the chaining mode
* *
* @throws EncryptedDocumentException if the given parameters mismatch, e.g. only certain combinations * @throws EncryptedDocumentException if the given parameters mismatch, e.g. only certain combinations
* of keyBits, blockSize are allowed for a given {@link CipherAlgorithm} * of keyBits, blockSize are allowed for a given {@link CipherAlgorithm}
@ -211,10 +205,11 @@ public class EncryptionInfo implements Cloneable {
* *
* @param encryptionMode the encryption mode * @param encryptionMode the encryption mode
* @return an encryption info builder * @return an encryption info builder
* @throws ClassNotFoundException * @throws ClassNotFoundException if the builder class is not on the classpath
* @throws IllegalAccessException * @throws IllegalAccessException if the builder class can't be loaded
* @throws InstantiationException * @throws InstantiationException if the builder class can't be loaded
*/ */
@SuppressWarnings("WeakerAccess")
protected static EncryptionInfoBuilder getBuilder(EncryptionMode encryptionMode) protected static EncryptionInfoBuilder getBuilder(EncryptionMode encryptionMode)
throws ClassNotFoundException, IllegalAccessException, InstantiationException { throws ClassNotFoundException, IllegalAccessException, InstantiationException {
ClassLoader cl = EncryptionInfo.class.getClassLoader(); ClassLoader cl = EncryptionInfo.class.getClassLoader();

View File

@ -26,7 +26,6 @@ import javax.crypto.spec.SecretKeySpec;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public abstract class Encryptor implements Cloneable { public abstract class Encryptor implements Cloneable {
@ -55,9 +54,6 @@ public abstract class Encryptor implements Cloneable {
public OutputStream getDataStream(NPOIFSFileSystem fs) throws IOException, GeneralSecurityException { public OutputStream getDataStream(NPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot()); return getDataStream(fs.getRoot());
} }
public OutputStream getDataStream(OPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot());
}
public OutputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException { public OutputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException {
return getDataStream(fs.getRoot()); return getDataStream(fs.getRoot());
} }

View File

@ -0,0 +1,35 @@
/* ====================================================================
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.
==================================================================== */
/**
* Implementation of the ECMA-376 and MS-propritary document encryptions<p>
*
* The implementation is split into the following packages:<p>
*
* <ul>
* <li>This package contains common functions for both current implemented cipher modes.</li>
* <li>the {@link org.apache.poi.poifs.crypt.agile agile} package is part of the poi ooxml jar and the provides agile encryption support.</li>
* <li>the {@link org.apache.poi.poifs.crypt.binaryrc4 binaryrc} package is used for the fixed length RC4 encryption of biff/H**F formats</li>
* <li>the {@link org.apache.poi.poifs.crypt.cryptoapi cryptoapi} package is used for the variable length RC encryption of biff/H**F formats</li>
* <li>the {@link org.apache.poi.poifs.crypt.standard standard} package contains classes for the standard encryption ...</li>
* <li>the {@link org.apache.poi.poifs.crypt.xor xor} package contains classes for the xor obfuscation of biff/H**F formats</li>
* </ul>
*
* @see <a href="http://poi.apache.org/encryption.html">Apache POI - Encryption support</a>
* @see <a href="http://msdn.microsoft.com/en-us/library/dd952186(v=office.12).aspx">ECMA-376 Document Encryption</a>
*/
package org.apache.poi.poifs.crypt;

View File

@ -1,44 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!--
====================================================================
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.
====================================================================
-->
<html>
<head>
</head>
<body bgcolor="white">
<p>Implementation of the <a href="http://msdn.microsoft.com/en-us/library/dd952186(v=office.12).aspx">ECMA-376 Document Encryption</a></p>
<p>The implementation is split into three packages:</p>
<ul>
<li>This package contains common functions for both current implemented cipher modes.</li>
<li>the {@link org.apache.poi.poifs.crypt.standard standard} package is part of the base poi jar and contains classes for the standard encryption ...</li>
<li>the {@link org.apache.poi.poifs.crypt.agile agile} package is part of the poi ooxml jar and the provides agile encryption support.</li>
</ul>
<h2>Related Documentation</h2>
Some implementations informations can be found under:
<ul>
<li><a href="http://poi.apache.org/encryption.html">Apache POI - Encryption support</a>
</ul>
<!-- Put @see and @since tags down here. -->
@see org.apache.poi.poifs.crypt.standard
@see org.apache.poi.poifs.crypt.agile
</body>
</html>

View File

@ -1,181 +0,0 @@
/* ====================================================================
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.poifs.dev;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.ListManagedBlock;
import org.apache.poi.poifs.storage.RawDataBlockList;
import org.apache.poi.poifs.storage.SmallBlockTableReader;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.IntList;
/**
* A very low level debugging tool, for printing out core
* information on the headers and FAT blocks.
* You probably only want to use this if you're trying
* to understand POIFS, or if you're trying to track
* down the source of corruption in a file.
*/
public class POIFSHeaderDumper {
/**
* Display the entries of multiple POIFS files
*
* @param args the names of the files to be displayed
*/
public static void main(final String args[]) throws Exception {
if (args.length == 0) {
System.err.println("Must specify at least one file to view");
System.exit(1);
}
for (int j = 0; j < args.length; j++) {
viewFile(args[j]);
}
}
public static void viewFile(final String filename) throws Exception {
System.out.println("Dumping headers from: " + filename);
InputStream inp = new FileInputStream(filename);
// Header
HeaderBlock header_block = new HeaderBlock(inp);
displayHeader(header_block);
// Raw blocks
POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize();
RawDataBlockList data_blocks = new RawDataBlockList(inp, bigBlockSize);
displayRawBlocksSummary(data_blocks);
// Main FAT Table
BlockAllocationTableReader batReader =
new BlockAllocationTableReader(
header_block.getBigBlockSize(),
header_block.getBATCount(),
header_block.getBATArray(),
header_block.getXBATCount(),
header_block.getXBATIndex(),
data_blocks);
displayBATReader("Big Blocks", batReader);
// Properties Table
PropertyTable properties =
new PropertyTable(header_block, data_blocks);
// Mini Fat
BlockAllocationTableReader sbatReader =
SmallBlockTableReader._getSmallDocumentBlockReader(
bigBlockSize, data_blocks, properties.getRoot(),
header_block.getSBATStart()
);
displayBATReader("Small Blocks", sbatReader);
// Summary of the properties
displayPropertiesSummary(properties);
}
public static void displayHeader(HeaderBlock header_block) throws Exception {
System.out.println("Header Details:");
System.out.println(" Block size: " + header_block.getBigBlockSize().getBigBlockSize());
System.out.println(" BAT (FAT) header blocks: " + header_block.getBATArray().length);
System.out.println(" BAT (FAT) block count: " + header_block.getBATCount());
if (header_block.getBATCount() > 0)
System.out.println(" BAT (FAT) block 1 at: " + header_block.getBATArray()[0]);
System.out.println(" XBAT (FAT) block count: " + header_block.getXBATCount());
System.out.println(" XBAT (FAT) block 1 at: " + header_block.getXBATIndex());
System.out.println(" SBAT (MiniFAT) block count: " + header_block.getSBATCount());
System.out.println(" SBAT (MiniFAT) block 1 at: " + header_block.getSBATStart());
System.out.println(" Property table at: " + header_block.getPropertyStart());
System.out.println("");
}
public static void displayRawBlocksSummary(RawDataBlockList data_blocks) throws Exception {
System.out.println("Raw Blocks Details:");
System.out.println(" Number of blocks: " + data_blocks.blockCount());
for(int i=0; i<Math.min(16, data_blocks.blockCount()); i++) {
ListManagedBlock block = data_blocks.get(i);
byte[] data = new byte[Math.min(48, block.getData().length)];
System.arraycopy(block.getData(), 0, data, 0, data.length);
System.out.println(" Block #" + i + ":");
System.out.println(HexDump.dump(data, 0, 0));
}
System.out.println("");
}
public static void displayBATReader(String type, BlockAllocationTableReader batReader) throws Exception {
System.out.println("Sectors, as referenced from the "+type+" FAT:");
IntList entries = batReader.getEntries();
for(int i=0; i<entries.size(); i++) {
int bn = entries.get(i);
String bnS = Integer.toString(bn);
if(bn == POIFSConstants.END_OF_CHAIN) {
bnS = "End Of Chain";
} else if(bn == POIFSConstants.DIFAT_SECTOR_BLOCK) {
bnS = "DI Fat Block";
} else if(bn == POIFSConstants.FAT_SECTOR_BLOCK) {
bnS = "Normal Fat Block";
} else if(bn == POIFSConstants.UNUSED_BLOCK) {
bnS = "Block Not Used (Free)";
}
System.out.println(" Block # " + i + " -> " + bnS);
}
System.out.println("");
}
public static void displayPropertiesSummary(PropertyTable properties) {
System.out.println("Mini Stream starts at " + properties.getRoot().getStartBlock());
System.out.println("Mini Stream length is " + properties.getRoot().getSize());
System.out.println();
System.out.println("Properties and their block start:");
displayProperties(properties.getRoot(), "");
System.out.println("");
}
public static void displayProperties(DirectoryProperty prop, String indent) {
String nextIndent = indent + " ";
System.out.println(indent + "-> " + prop.getName());
for (Property cp : prop) {
if (cp instanceof DirectoryProperty) {
displayProperties((DirectoryProperty)cp, nextIndent);
} else {
System.out.println(nextIndent + "=> " + cp.getName());
System.out.print(nextIndent + " " + cp.getSize() + " bytes in ");
if (cp.shouldUseSmallBlocks()) {
System.out.print("mini");
} else {
System.out.print("main");
}
System.out.println(" stream, starts at " + cp.getStartBlock());
}
}
}
}

View File

@ -1,6 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> /* ====================================================================
<!--
====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership. this work for additional information regarding copyright ownership.
@ -15,21 +13,14 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== ==================================================================== */
-->
<html>
<head>
</head>
<body bgcolor="white">
common package contains constants and other classes shared across all POIFS subpackages /**
* DEV package serves two purposes.
<h2>Related Documentation</h2> *
* <ol>
For overviews, tutorials, examples, guides, and tool documentation, please see: * <li>Examples for how to use POIFS</li>
<ul> * <li>tools for developing and validating POIFS</li>
<li><a href="http://poi.apache.org">Apache POI Project</a> * </ol>
</ul> */
package org.apache.poi.poifs.dev;
</body>
</html>

View File

@ -19,23 +19,19 @@
package org.apache.poi.poifs.eventfilesystem; package org.apache.poi.poifs.eventfilesystem;
import java.io.FileInputStream; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Iterator;
import org.apache.poi.poifs.filesystem.DocumentInputStream; import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.OPOIFSDocument; import org.apache.poi.poifs.filesystem.NPOIFSDocument;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSDocumentPath; import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
import org.apache.poi.poifs.property.DirectoryProperty; import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.DocumentProperty;
import org.apache.poi.poifs.property.NPropertyTable;
import org.apache.poi.poifs.property.Property; import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.property.RootProperty; import org.apache.poi.poifs.property.RootProperty;
import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.BlockList;
import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.RawDataBlockList;
import org.apache.poi.poifs.storage.SmallBlockTableReader;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
/** /**
@ -49,19 +45,10 @@ import org.apache.poi.util.IOUtils;
public class POIFSReader public class POIFSReader
{ {
private final POIFSReaderRegistry registry; private final POIFSReaderRegistry registry = new POIFSReaderRegistry();
private boolean registryClosed; private boolean registryClosed = false;
private boolean notifyEmptyDirectories; private boolean notifyEmptyDirectories;
// private NPOIFSFileSystem poifs;
/**
* Create a POIFSReader
*/
public POIFSReader()
{
registry = new POIFSReaderRegistry();
registryClosed = false;
}
/** /**
* Read from an InputStream and process the documents we get * Read from an InputStream and process the documents we get
@ -71,40 +58,41 @@ public class POIFSReader
* @exception IOException on errors reading, or on invalid data * @exception IOException on errors reading, or on invalid data
*/ */
public void read(final InputStream stream) public void read(final InputStream stream) throws IOException {
throws IOException try (NPOIFSFileSystem poifs = new NPOIFSFileSystem(stream)) {
{ read(poifs);
}
}
/**
* Read from a File and process the documents we get
*
* @param poifsFile the file from which to read the data
*
* @exception IOException on errors reading, or on invalid data
*/
public void read(final File poifsFile) throws IOException {
try (NPOIFSFileSystem poifs = new NPOIFSFileSystem(poifsFile, true)) {
read(poifs);
}
}
/**
* Read from a NPOIFSFileSystem and process the documents we get
*
* @param poifs the NPOIFSFileSystem from which to read the data
*
* @exception IOException on errors reading, or on invalid data
*/
public void read(final NPOIFSFileSystem poifs) throws IOException {
registryClosed = true; registryClosed = true;
// read the header block from the stream
HeaderBlock header_block = new HeaderBlock(stream);
// read the rest of the stream into blocks
RawDataBlockList data_blocks = new RawDataBlockList(stream, header_block.getBigBlockSize());
// set up the block allocation table (necessary for the
// data_blocks to be manageable
new BlockAllocationTableReader(header_block.getBigBlockSize(),
header_block.getBATCount(),
header_block.getBATArray(),
header_block.getXBATCount(),
header_block.getXBATIndex(),
data_blocks);
// get property table from the document // get property table from the document
PropertyTable properties = NPropertyTable properties = poifs.getPropertyTable();
new PropertyTable(header_block, data_blocks);
// process documents // process documents
RootProperty root = properties.getRoot(); RootProperty root = properties.getRoot();
processProperties(SmallBlockTableReader processProperties(poifs, root, new POIFSDocumentPath());
.getSmallDocumentBlocks(
header_block.getBigBlockSize(),
data_blocks, root,
header_block.getSBATStart()
),
data_blocks, root.getChildren(), new POIFSDocumentPath()
);
} }
/** /**
@ -117,14 +105,11 @@ public class POIFSReader
* called * called
*/ */
public void registerListener(final POIFSReaderListener listener) public void registerListener(final POIFSReaderListener listener) {
{ if (listener == null) {
if (listener == null)
{
throw new NullPointerException(); throw new NullPointerException();
} }
if (registryClosed) if (registryClosed) {
{
throw new IllegalStateException(); throw new IllegalStateException();
} }
registry.registerListener(listener); registry.registerListener(listener);
@ -143,9 +128,7 @@ public class POIFSReader
* called * called
*/ */
public void registerListener(final POIFSReaderListener listener, public void registerListener(final POIFSReaderListener listener, final String name) {
final String name)
{
registerListener(listener, null, name); registerListener(listener, null, name);
} }
@ -166,19 +149,14 @@ public class POIFSReader
public void registerListener(final POIFSReaderListener listener, public void registerListener(final POIFSReaderListener listener,
final POIFSDocumentPath path, final POIFSDocumentPath path,
final String name) final String name) {
{ if ((listener == null) || (name == null) || (name.length() == 0)) {
if ((listener == null) || (name == null) || (name.length() == 0))
{
throw new NullPointerException(); throw new NullPointerException();
} }
if (registryClosed) if (registryClosed) {
{
throw new IllegalStateException(); throw new IllegalStateException();
} }
registry.registerListener(listener, registry.registerListener(listener, (path == null) ? new POIFSDocumentPath() : path, name);
(path == null) ? new POIFSDocumentPath()
: path, name);
} }
/** /**
@ -186,7 +164,7 @@ public class POIFSReader
* If this flag is activated, the {@link POIFSReaderListener listener} receives * If this flag is activated, the {@link POIFSReaderListener listener} receives
* {@link POIFSReaderEvent POIFSReaderEvents} with nulled {@code name} and {@code stream} * {@link POIFSReaderEvent POIFSReaderEvents} with nulled {@code name} and {@code stream}
* *
* @param notifyEmptyDirectories * @param notifyEmptyDirectories if {@code true}, empty directories will be notified
*/ */
public void setNotifyEmptyDirectories(boolean notifyEmptyDirectories) { public void setNotifyEmptyDirectories(boolean notifyEmptyDirectories) {
this.notifyEmptyDirectories = notifyEmptyDirectories; this.notifyEmptyDirectories = notifyEmptyDirectories;
@ -198,139 +176,72 @@ public class POIFSReader
* *
* @param args names of the files * @param args names of the files
* *
* @exception IOException * @exception IOException if the files can't be read or have invalid content
*/ */
public static void main(String args[]) public static void main(String args[]) throws IOException {
throws IOException if (args.length == 0) {
{
if (args.length == 0)
{
System.err.println("at least one argument required: input filename(s)"); System.err.println("at least one argument required: input filename(s)");
System.exit(1); System.exit(1);
} }
// register for all // register for all
for (String arg : args) for (String arg : args) {
{ POIFSReader reader = new POIFSReader();
POIFSReader reader = new POIFSReader(); reader.registerListener(POIFSReader::readEntry);
POIFSReaderListener listener = new SampleListener();
reader.registerListener(listener);
System.out.println("reading " + arg); System.out.println("reading " + arg);
FileInputStream istream = new FileInputStream(arg);
reader.read(istream); reader.read(new File(arg));
istream.close();
} }
} }
private void processProperties(final BlockList small_blocks, private static void readEntry(POIFSReaderEvent event) {
final BlockList big_blocks, POIFSDocumentPath path = event.getPath();
final Iterator<Property> properties, StringBuilder sb = new StringBuilder();
final POIFSDocumentPath path)
throws IOException {
if (!properties.hasNext() && notifyEmptyDirectories) {
Iterator<POIFSReaderListener> listeners = registry.getListeners(path, ".");
while (listeners.hasNext()) {
POIFSReaderListener pl = listeners.next();
POIFSReaderEvent pe = new POIFSReaderEvent(null, path, null);
pl.processPOIFSReaderEvent(pe);
}
return;
}
while (properties.hasNext()) try (DocumentInputStream istream = event.getStream()) {
{ sb.setLength(0);
Property property = properties.next(); int pathLength = path.length();
String name = property.getName(); for (int k = 0; k < pathLength; k++) {
sb.append("/").append(path.getComponent(k));
}
byte[] data = IOUtils.toByteArray(istream);
sb.append("/").append(event.getName()).append(": ").append(data.length).append(" bytes read");
System.out.println(sb);
} catch (IOException ignored) {
}
}
private void processProperties(final NPOIFSFileSystem poifs, DirectoryProperty dir, final POIFSDocumentPath path) {
boolean hasChildren = false;
for (final Property property : dir) {
hasChildren = true;
String name = property.getName();
if (property.isDirectory()) { if (property.isDirectory()) {
POIFSDocumentPath new_path = new POIFSDocumentPath(path,new String[]{name}); POIFSDocumentPath new_path = new POIFSDocumentPath(path,new String[]{name});
DirectoryProperty dp = (DirectoryProperty) property; processProperties(poifs, (DirectoryProperty) property, new_path);
processProperties(small_blocks, big_blocks, dp.getChildren(), new_path);
} else { } else {
int startBlock = property.getStartBlock(); NPOIFSDocument document = null;
Iterator<POIFSReaderListener> listeners = registry.getListeners(path, name); for (POIFSReaderListener rl : registry.getListeners(path, name)) {
if (document == null) {
if (listeners.hasNext()) document = new NPOIFSDocument((DocumentProperty)property, poifs);
{
int size = property.getSize();
OPOIFSDocument document = null;
if (property.shouldUseSmallBlocks())
{
document =
new OPOIFSDocument(name, small_blocks
.fetchBlocks(startBlock, -1), size);
} }
else try (DocumentInputStream dis = new DocumentInputStream(document)) {
{ POIFSReaderEvent pe = new POIFSReaderEvent(dis, path, name);
document = rl.processPOIFSReaderEvent(pe);
new OPOIFSDocument(name, big_blocks
.fetchBlocks(startBlock, -1), size);
}
while (listeners.hasNext())
{
POIFSReaderListener listener = listeners.next();
try (DocumentInputStream dis = new DocumentInputStream(document)) {
listener.processPOIFSReaderEvent(new POIFSReaderEvent(dis, path, name));
}
}
}
else
{
// consume the document's data and discard it
if (property.shouldUseSmallBlocks())
{
small_blocks.fetchBlocks(startBlock, -1);
}
else
{
big_blocks.fetchBlocks(startBlock, -1);
} }
} }
} }
} }
}
private static class SampleListener if (hasChildren || !notifyEmptyDirectories) {
implements POIFSReaderListener return;
{
/**
* Constructor SampleListener
*/
SampleListener()
{
} }
/** for (POIFSReaderListener rl : registry.getListeners(path, ".")) {
* Method processPOIFSReaderEvent POIFSReaderEvent pe = new POIFSReaderEvent(null, path, null);
* rl.processPOIFSReaderEvent(pe);
* @param event
*/
@Override
public void processPOIFSReaderEvent(final POIFSReaderEvent event) {
DocumentInputStream istream = event.getStream();
POIFSDocumentPath path = event.getPath();
String name = event.getName();
try {
byte[] data = IOUtils.toByteArray(istream);
int pathLength = path.length();
for (int k = 0; k < pathLength; k++) {
System.out.print("/" + path.getComponent(k));
}
System.out.println("/" + name + ": " + data.length + " bytes read");
} catch (IOException ignored) {
} finally {
IOUtils.closeQuietly(istream);
}
} }
} }
} }

View File

@ -79,34 +79,21 @@ class POIFSReaderRegistry
// not an omnivorous listener (if it was, this method is a // not an omnivorous listener (if it was, this method is a
// no-op) // no-op)
Set<DocumentDescriptor> descriptors = selectiveListeners.get(listener); Set<DocumentDescriptor> descriptors =
selectiveListeners.computeIfAbsent(listener, k -> new HashSet<>());
if (descriptors == null) // this listener has not registered before
{ DocumentDescriptor descriptor = new DocumentDescriptor(path, documentName);
// this listener has not registered before if (descriptors.add(descriptor)) {
descriptors = new HashSet<>();
selectiveListeners.put(listener, descriptors);
}
DocumentDescriptor descriptor = new DocumentDescriptor(path,
documentName);
if (descriptors.add(descriptor))
{
// this listener wasn't already listening for this // this listener wasn't already listening for this
// document -- add the listener to the set of // document -- add the listener to the set of
// listeners for this document // listeners for this document
Set<POIFSReaderListener> listeners = Set<POIFSReaderListener> listeners =
chosenDocumentDescriptors.get(descriptor); chosenDocumentDescriptors.computeIfAbsent(descriptor, k -> new HashSet<>());
if (listeners == null) // nobody was listening for this document before
{
// nobody was listening for this document before
listeners = new HashSet<>();
chosenDocumentDescriptors.put(descriptor, listeners);
}
listeners.add(listener); listeners.add(listener);
} }
} }
@ -141,7 +128,7 @@ class POIFSReaderRegistry
* @return an Iterator POIFSReaderListeners; may be empty * @return an Iterator POIFSReaderListeners; may be empty
*/ */
Iterator<POIFSReaderListener> getListeners(final POIFSDocumentPath path, final String name) Iterable<POIFSReaderListener> getListeners(final POIFSDocumentPath path, final String name)
{ {
Set<POIFSReaderListener> rval = new HashSet<>(omnivorousListeners); Set<POIFSReaderListener> rval = new HashSet<>(omnivorousListeners);
Set<POIFSReaderListener> selectiveListenersInner = Set<POIFSReaderListener> selectiveListenersInner =
@ -151,20 +138,16 @@ class POIFSReaderRegistry
{ {
rval.addAll(selectiveListenersInner); rval.addAll(selectiveListenersInner);
} }
return rval.iterator(); return rval;
} }
private void removeSelectiveListener(final POIFSReaderListener listener) private void removeSelectiveListener(final POIFSReaderListener listener)
{ {
Set<DocumentDescriptor> selectedDescriptors = selectiveListeners.remove(listener); Set<DocumentDescriptor> selectedDescriptors = selectiveListeners.remove(listener);
if (selectedDescriptors != null) if (selectedDescriptors != null) {
{ for (DocumentDescriptor selectedDescriptor : selectedDescriptors) {
Iterator<DocumentDescriptor> iter = selectedDescriptors.iterator(); dropDocument(listener, selectedDescriptor);
while (iter.hasNext())
{
dropDocument(listener, iter.next());
} }
} }
} }

View File

@ -1,6 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> /* ====================================================================
<!--
====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership. this work for additional information regarding copyright ownership.
@ -15,22 +13,11 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== ==================================================================== */
-->
<html>
<head>
</head>
<body bgcolor="white">
DEV package serves two purposes. 1. Examples for how to use POIFS and 2. tools for developing /**
and validating POIFS. * The eventfilesystem is an efficient method for reading OLE 2 CDF files. It is to OLE 2 CDF what SAX is to XML.
*
<h2>Related Documentation</h2> * @see org.apache.poi.poifs.filesystem
*/
For overviews, tutorials, examples, guides, and tool documentation, please see: package org.apache.poi.poifs.eventfilesystem;
<ul>
<li><a href="http://poi.apache.org">Apache POI Project</a>
</ul>
</body>
</html>

View File

@ -1,37 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!--
====================================================================
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.
====================================================================
-->
<html>
<head>
</head>
<body bgcolor="white">
The eventfilesystem is an efficient method for reading OLE 2 CDF files. It is to OLE 2 CDF what SAX is to XML.
<h2>Related Documentation</h2>
For overviews, tutorials, examples, guides, and tool documentation, please see:
<ul>
<li><a href="http://poi.apache.org">Apache POI Project</a>
</ul>
<!-- Put @see and @since tags down here. -->
@see org.apache.poi.poifs.filesystem
</body>
</html>

View File

@ -44,33 +44,16 @@ public class DirectoryNode
{ {
// Map of Entry instances, keyed by their names // Map of Entry instances, keyed by their names
private Map<String,Entry> _byname; private final Map<String,Entry> _byname = new HashMap<>();
// Our list of entries, kept sorted to preserve order
private ArrayList<Entry> _entries; // Our list of entries, kept sorted to preserve order
private final ArrayList<Entry> _entries = new ArrayList<>();
// Only one of these two will exist
// the OPOIFSFileSystem we belong to
private OPOIFSFileSystem _ofilesystem;
// the NPOIFSFileSytem we belong to // the NPOIFSFileSytem we belong to
private NPOIFSFileSystem _nfilesystem; private final NPOIFSFileSystem _nfilesystem;
// the path described by this document // the path described by this document
private POIFSDocumentPath _path; private final POIFSDocumentPath _path;
/**
* create a DirectoryNode. This method is not public by design; it
* is intended strictly for the internal use of this package
*
* @param property the DirectoryProperty for this DirectoryEntry
* @param filesystem the OPOIFSFileSystem we belong to
* @param parent the parent of this entry
*/
DirectoryNode(final DirectoryProperty property,
final OPOIFSFileSystem filesystem,
final DirectoryNode parent)
{
this(property, parent, filesystem, null);
}
/** /**
* create a DirectoryNode. This method is not public by design; it * create a DirectoryNode. This method is not public by design; it
@ -83,17 +66,8 @@ public class DirectoryNode
DirectoryNode(final DirectoryProperty property, DirectoryNode(final DirectoryProperty property,
final NPOIFSFileSystem nfilesystem, final NPOIFSFileSystem nfilesystem,
final DirectoryNode parent) final DirectoryNode parent)
{
this(property, parent, null, nfilesystem);
}
private DirectoryNode(final DirectoryProperty property,
final DirectoryNode parent,
final OPOIFSFileSystem ofilesystem,
final NPOIFSFileSystem nfilesystem)
{ {
super(property, parent); super(property, parent);
this._ofilesystem = ofilesystem;
this._nfilesystem = nfilesystem; this._nfilesystem = nfilesystem;
if (parent == null) if (parent == null)
@ -103,12 +77,10 @@ public class DirectoryNode
else else
{ {
_path = new POIFSDocumentPath(parent._path, new String[] _path = new POIFSDocumentPath(parent._path, new String[]
{ {
property.getName() property.getName()
}); });
} }
_byname = new HashMap<>();
_entries = new ArrayList<>();
Iterator<Property> iter = property.getChildren(); Iterator<Property> iter = property.getChildren();
while (iter.hasNext()) while (iter.hasNext())
@ -119,11 +91,7 @@ public class DirectoryNode
if (child.isDirectory()) if (child.isDirectory())
{ {
DirectoryProperty childDir = (DirectoryProperty) child; DirectoryProperty childDir = (DirectoryProperty) child;
if(_ofilesystem != null) { childNode = new DirectoryNode(childDir, _nfilesystem, this);
childNode = new DirectoryNode(childDir, _ofilesystem, this);
} else {
childNode = new DirectoryNode(childDir, _nfilesystem, this);
}
} }
else else
{ {
@ -151,15 +119,6 @@ public class DirectoryNode
return _nfilesystem; return _nfilesystem;
} }
/**
* If this is OPOIFS based, return the NPOIFSFileSystem
* that this belong to, otherwise Null if NPOIFS based
* @return the filesystem that this belongs to
*/
public OPOIFSFileSystem getOFileSystem()
{
return _ofilesystem;
}
/** /**
* If this is NPOIFS based, return the NPOIFSFileSystem * If this is NPOIFS based, return the NPOIFSFileSystem
@ -218,30 +177,7 @@ public class DirectoryNode
* *
* @return the new DocumentEntry * @return the new DocumentEntry
* *
* @exception IOException * @exception IOException if the document can't be created
*/
DocumentEntry createDocument(final OPOIFSDocument document)
throws IOException
{
DocumentProperty property = document.getDocumentProperty();
DocumentNode rval = new DocumentNode(property, this);
(( DirectoryProperty ) getProperty()).addChild(property);
_ofilesystem.addDocument(document);
_entries.add(rval);
_byname.put(property.getName(), rval);
return rval;
}
/**
* create a new DocumentEntry
*
* @param document the new document
*
* @return the new DocumentEntry
*
* @exception IOException
*/ */
DocumentEntry createDocument(final NPOIFSDocument document) DocumentEntry createDocument(final NPOIFSDocument document)
throws IOException throws IOException
@ -302,14 +238,11 @@ public class DirectoryNode
_entries.remove(entry); _entries.remove(entry);
_byname.remove(entry.getName()); _byname.remove(entry.getName());
if(_ofilesystem != null) { try {
_ofilesystem.remove(entry); _nfilesystem.remove(entry);
} else { } catch (IOException e) {
try { // TODO Work out how to report this, given we can't change the method signature...
_nfilesystem.remove(entry); throw new RuntimeException(e);
} catch (IOException e) {
// TODO Work out how to report this, given we can't change the method signature...
}
} }
} }
return rval; return rval;
@ -411,18 +344,14 @@ public class DirectoryNode
* *
* @return the new DocumentEntry * @return the new DocumentEntry
* *
* @exception IOException * @exception IOException if the document can't be created
*/ */
public DocumentEntry createDocument(final String name, public DocumentEntry createDocument(final String name,
final InputStream stream) final InputStream stream)
throws IOException throws IOException
{ {
if(_nfilesystem != null) { return createDocument(new NPOIFSDocument(name, _nfilesystem, stream));
return createDocument(new NPOIFSDocument(name, _nfilesystem, stream));
} else {
return createDocument(new OPOIFSDocument(name, stream));
}
} }
/** /**
@ -434,18 +363,14 @@ public class DirectoryNode
* *
* @return the new DocumentEntry * @return the new DocumentEntry
* *
* @exception IOException * @exception IOException if the document can't be created
*/ */
public DocumentEntry createDocument(final String name, final int size, public DocumentEntry createDocument(final String name, final int size,
final POIFSWriterListener writer) final POIFSWriterListener writer)
throws IOException throws IOException
{ {
if(_nfilesystem != null) { return createDocument(new NPOIFSDocument(name, size, _nfilesystem, writer));
return createDocument(new NPOIFSDocument(name, size, _nfilesystem, writer));
} else {
return createDocument(new OPOIFSDocument(name, size, _path, writer));
}
} }
/** /**
@ -455,22 +380,16 @@ public class DirectoryNode
* *
* @return the new DirectoryEntry * @return the new DirectoryEntry
* *
* @exception IOException * @exception IOException if the directory can't be created
*/ */
public DirectoryEntry createDirectory(final String name) public DirectoryEntry createDirectory(final String name)
throws IOException throws IOException
{ {
DirectoryNode rval;
DirectoryProperty property = new DirectoryProperty(name); DirectoryProperty property = new DirectoryProperty(name);
if(_ofilesystem != null) { DirectoryNode rval = new DirectoryNode(property, _nfilesystem, this);
rval = new DirectoryNode(property, _ofilesystem, this); _nfilesystem.addDirectory(property);
_ofilesystem.addDirectory(property);
} else {
rval = new DirectoryNode(property, _nfilesystem, this);
_nfilesystem.addDirectory(property);
}
(( DirectoryProperty ) getProperty()).addChild(property); (( DirectoryProperty ) getProperty()).addChild(property);
_entries.add(rval); _entries.add(rval);
@ -487,9 +406,9 @@ public class DirectoryNode
* *
* @return the new or updated DocumentEntry * @return the new or updated DocumentEntry
* *
* @exception IOException * @exception IOException if the document can't be created or its content be replaced
*/ */
@SuppressWarnings("WeakerAccess")
public DocumentEntry createOrUpdateDocument(final String name, public DocumentEntry createOrUpdateDocument(final String name,
final InputStream stream) final InputStream stream)
throws IOException throws IOException
@ -498,15 +417,9 @@ public class DirectoryNode
return createDocument(name, stream); return createDocument(name, stream);
} else { } else {
DocumentNode existing = (DocumentNode)getEntry(name); DocumentNode existing = (DocumentNode)getEntry(name);
if (_nfilesystem != null) { NPOIFSDocument nDoc = new NPOIFSDocument(existing);
NPOIFSDocument nDoc = new NPOIFSDocument(existing); nDoc.replaceContents(stream);
nDoc.replaceContents(stream); return existing;
return existing;
} else {
// Do it the hard way for Old POIFS...
deleteEntry(existing);
return createDocument(name, stream);
}
} }
} }

View File

@ -20,7 +20,6 @@ package org.apache.poi.poifs.filesystem;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.SuppressForbidden; import org.apache.poi.util.SuppressForbidden;
@ -34,10 +33,6 @@ public class DocumentInputStream extends InputStream implements LittleEndianInpu
/** returned by read operations if we're at end of document */ /** returned by read operations if we're at end of document */
protected static final int EOF = -1; protected static final int EOF = -1;
protected static final int SIZE_SHORT = 2;
protected static final int SIZE_INT = 4;
protected static final int SIZE_LONG = 8;
private DocumentInputStream delegate; private DocumentInputStream delegate;
/** For use by downstream implementations */ /** For use by downstream implementations */
@ -55,27 +50,7 @@ public class DocumentInputStream extends InputStream implements LittleEndianInpu
if (!(document instanceof DocumentNode)) { if (!(document instanceof DocumentNode)) {
throw new IOException("Cannot open internal document storage"); throw new IOException("Cannot open internal document storage");
} }
DocumentNode documentNode = (DocumentNode)document; delegate = new NDocumentInputStream(document);
DirectoryNode parentNode = (DirectoryNode)document.getParent();
if(documentNode.getDocument() != null) {
delegate = new ODocumentInputStream(document);
} else if(parentNode.getOFileSystem() != null) {
delegate = new ODocumentInputStream(document);
} else if(parentNode.getNFileSystem() != null) {
delegate = new NDocumentInputStream(document);
} else {
throw new IOException("No FileSystem bound on the parent, can't read contents");
}
}
/**
* Create an InputStream from the specified Document
*
* @param document the Document to be read
*/
public DocumentInputStream(OPOIFSDocument document) {
delegate = new ODocumentInputStream(document);
} }
/** /**

View File

@ -35,7 +35,7 @@ public class DocumentNode
{ {
// underlying POIFSDocument instance // underlying POIFSDocument instance
private OPOIFSDocument _document; private NPOIFSDocument _document;
/** /**
* create a DocumentNode. This method is not public by design; it * create a DocumentNode. This method is not public by design; it
@ -56,7 +56,7 @@ public class DocumentNode
* *
* @return the internal POIFSDocument * @return the internal POIFSDocument
*/ */
OPOIFSDocument getDocument() NPOIFSDocument getDocument()
{ {
return _document; return _document;
} }

View File

@ -16,27 +16,31 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import java.io.FileNotFoundException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.poi.hpsf.MarkUnsupportedException;
import org.apache.poi.hpsf.NoPropertySetStreamException;
import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.PropertySetFactory;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
@Internal @Internal
public class EntryUtils public final class EntryUtils {
{ private EntryUtils() {}
/** /**
* Copies an Entry into a target POIFS directory, recursively * Copies an Entry into a target POIFS directory, recursively
*/ */
@Internal @Internal
public static void copyNodeRecursively( Entry entry, DirectoryEntry target ) public static void copyNodeRecursively( Entry entry, DirectoryEntry target )
throws IOException { throws IOException {
// logger.log( POILogger.ERROR, "copyNodeRecursively called with "+entry.getName()+
// ","+target.getName());
if ( entry.isDirectoryEntry() ) { if ( entry.isDirectoryEntry() ) {
DirectoryEntry dirEntry = (DirectoryEntry)entry; DirectoryEntry dirEntry = (DirectoryEntry)entry;
DirectoryEntry newTarget = target.createDirectory( entry.getName() ); DirectoryEntry newTarget = target.createDirectory( entry.getName() );
@ -62,8 +66,8 @@ public class EntryUtils
* @param targetRoot * @param targetRoot
* is the target Directory to copy to * is the target Directory to copy to
*/ */
public static void copyNodes(DirectoryEntry sourceRoot, public static void copyNodes(DirectoryEntry sourceRoot, DirectoryEntry targetRoot)
DirectoryEntry targetRoot) throws IOException { throws IOException {
for (Entry entry : sourceRoot) { for (Entry entry : sourceRoot) {
copyNodeRecursively( entry, targetRoot ); copyNodeRecursively( entry, targetRoot );
} }
@ -77,22 +81,8 @@ public class EntryUtils
* @param target * @param target
* is the target POIFS to copy to * is the target POIFS to copy to
*/ */
public static void copyNodes( OPOIFSFileSystem source, public static void copyNodes( NPOIFSFileSystem source, NPOIFSFileSystem target )
OPOIFSFileSystem target ) throws IOException throws IOException {
{
copyNodes( source.getRoot(), target.getRoot() );
}
/**
* Copies all nodes from one POIFS to the other
*
* @param source
* is the source POIFS to copy from
* @param target
* is the target POIFS to copy to
*/
public static void copyNodes( NPOIFSFileSystem source,
NPOIFSFileSystem target ) throws IOException
{
copyNodes( source.getRoot(), target.getRoot() ); copyNodes( source.getRoot(), target.getRoot() );
} }
@ -106,27 +96,8 @@ public class EntryUtils
* @param target is the target POIFS to copy to * @param target is the target POIFS to copy to
* @param excepts is a list of Entry Names to be excluded from the copy * @param excepts is a list of Entry Names to be excluded from the copy
*/ */
public static void copyNodes( OPOIFSFileSystem source, public static void copyNodes( NPOIFSFileSystem source, NPOIFSFileSystem target, List<String> excepts )
OPOIFSFileSystem target, List<String> excepts ) throws IOException throws IOException {
{
copyNodes(
new FilteringDirectoryNode(source.getRoot(), excepts),
new FilteringDirectoryNode(target.getRoot(), excepts)
);
}
/**
* Copies nodes from one POIFS to the other, minus the excepts.
* This delegates the filtering work to {@link FilteringDirectoryNode},
* so excepts can be of the form "NodeToExclude" or
* "FilteringDirectory/ExcludedChildNode"
*
* @param source is the source POIFS to copy from
* @param target is the target POIFS to copy to
* @param excepts is a list of Entry Names to be excluded from the copy
*/
public static void copyNodes( NPOIFSFileSystem source,
NPOIFSFileSystem target, List<String> excepts ) throws IOException
{
copyNodes( copyNodes(
new FilteringDirectoryNode(source.getRoot(), excepts), new FilteringDirectoryNode(source.getRoot(), excepts),
new FilteringDirectoryNode(target.getRoot(), excepts) new FilteringDirectoryNode(target.getRoot(), excepts)
@ -142,114 +113,137 @@ public class EntryUtils
* use a {@link FilteringDirectoryNode} * use a {@link FilteringDirectoryNode}
*/ */
public static boolean areDirectoriesIdentical(DirectoryEntry dirA, DirectoryEntry dirB) { public static boolean areDirectoriesIdentical(DirectoryEntry dirA, DirectoryEntry dirB) {
// First, check names return new DirectoryDelegate(dirA).equals(new DirectoryDelegate(dirB));
if (! dirA.getName().equals(dirB.getName())) {
return false;
}
// Next up, check they have the same number of children
if (dirA.getEntryCount() != dirB.getEntryCount()) {
return false;
}
// Next, check entries and their types/sizes
Map<String,Integer> aSizes = new HashMap<>();
final int isDirectory = -12345;
for (Entry a : dirA) {
String aName = a.getName();
if (a.isDirectoryEntry()) {
aSizes.put(aName, isDirectory);
} else {
aSizes.put(aName, ((DocumentNode)a).getSize());
}
}
for (Entry b : dirB) {
String bName = b.getName();
if (! aSizes.containsKey(bName)) {
// In B but not A
return false;
}
int size;
if (b.isDirectoryEntry()) {
size = isDirectory;
} else {
size = ((DocumentNode)b).getSize();
}
if (size != aSizes.get(bName)) {
// Either the wrong type, or they're different sizes
return false;
}
// Track it as checked
aSizes.remove(bName);
}
if (!aSizes.isEmpty()) {
// Nodes were in A but not B
return false;
}
// If that passed, check entry contents
for (Entry a : dirA) {
try {
Entry b = dirB.getEntry(a.getName());
boolean match;
if (a.isDirectoryEntry()) {
match = areDirectoriesIdentical(
(DirectoryEntry)a, (DirectoryEntry)b);
} else {
match = areDocumentsIdentical(
(DocumentEntry)a, (DocumentEntry)b);
}
if (!match) return false;
} catch(FileNotFoundException e) {
// Shouldn't really happen...
return false;
} catch(IOException e) {
// Something's messed up with one document, not a match
return false;
}
}
// If we get here, they match!
return true;
} }
/** /**
* Checks to see if two Documents have the same name * Compares two {@link DocumentEntry} instances of a POI file system.
* and the same contents. (Their parent directories are * Documents that are not property set streams must be bitwise identical.
* not checked) * Property set streams must be logically equal.<p>
*
* (Their parent directories are not checked)
*/ */
public static boolean areDocumentsIdentical(DocumentEntry docA, DocumentEntry docB) throws IOException { @SuppressWarnings("WeakerAccess")
if (! docA.getName().equals(docB.getName())) { public static boolean areDocumentsIdentical(DocumentEntry docA, DocumentEntry docB)
// Names don't match, not the same throws IOException {
return false; try {
} return new DocumentDelegate(docA).equals(new DocumentDelegate(docB));
if (docA.getSize() != docB.getSize()) { } catch (RuntimeException e) {
// Wrong sizes, can't have the same contents if (e.getCause() instanceof IOException) {
return false; throw (IOException)e.getCause();
} } else {
throw e;
}
}
}
boolean matches = true; private interface POIDelegate {
DocumentInputStream inpA = null, inpB = null; }
try {
inpA = new DocumentInputStream(docA); private static class DirectoryDelegate implements POIDelegate {
inpB = new DocumentInputStream(docB); final DirectoryEntry dir;
int readA, readB; DirectoryDelegate(DirectoryEntry dir) {
do { this.dir = dir;
readA = inpA.read(); }
readB = inpB.read();
if (readA != readB) { private Map<String,POIDelegate> entries() {
matches = false; return StreamSupport.stream(dir.spliterator(), false)
break; .collect(Collectors.toMap(Entry::getName, DirectoryDelegate::toDelegate));
} }
} while(readA != -1 && readB != -1);
} finally { private static POIDelegate toDelegate(Entry entry) {
if (inpA != null) inpA.close(); return (entry.isDirectoryEntry())
if (inpB != null) inpB.close(); ? new DirectoryDelegate((DirectoryEntry)entry)
} : new DocumentDelegate((DocumentEntry)entry);
}
return matches;
@Override
public boolean equals(Object other) {
if (!(other instanceof DirectoryDelegate)) {
return false;
}
DirectoryDelegate dd = (DirectoryDelegate)other;
if (this == dd) {
return true;
}
// First, check names
if (!Objects.equals(dir.getName(),dd.dir.getName())) {
return false;
}
// Next up, check they have the same number of children
if (dir.getEntryCount() != dd.dir.getEntryCount()) {
return false;
}
return entries().equals(dd.entries());
}
}
private static class DocumentDelegate implements POIDelegate {
final DocumentEntry doc;
DocumentDelegate(DocumentEntry doc) {
this.doc = doc;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof DocumentDelegate)) {
return false;
}
DocumentDelegate dd = (DocumentDelegate)other;
if (this == dd) {
return true;
}
if (!Objects.equals(doc.getName(), dd.doc.getName())) {
// Names don't match, not the same
return false;
}
try (DocumentInputStream inpA = new DocumentInputStream(doc);
DocumentInputStream inpB = new DocumentInputStream(dd.doc)) {
if (PropertySet.isPropertySetStream(inpA) &&
PropertySet.isPropertySetStream(inpB)) {
final PropertySet ps1 = PropertySetFactory.create(inpA);
final PropertySet ps2 = PropertySetFactory.create(inpB);
return ps1.equals(ps2);
} else {
return isEqual(inpA, inpB);
}
} catch (MarkUnsupportedException | NoPropertySetStreamException | IOException ex) {
throw new RuntimeException(ex);
}
}
private static boolean isEqual(DocumentInputStream i1, DocumentInputStream i2)
throws IOException {
final byte[] buf1 = new byte[4*1024];
final byte[] buf2 = new byte[4*1024];
try {
int len;
while ((len = i1.read(buf1)) > 0) {
i2.readFully(buf2,0,len);
for(int i=0;i<len;i++) {
if (buf1[i] != buf2[i]) {
return false;
}
}
}
// is the end of the second file also.
return i2.read() < 0;
} catch(EOFException | RuntimeException ioe) {
return false;
}
}
} }
} }

View File

@ -17,6 +17,10 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static org.apache.poi.util.LittleEndianConsts.INT_SIZE;
import static org.apache.poi.util.LittleEndianConsts.LONG_SIZE;
import static org.apache.poi.util.LittleEndianConsts.SHORT_SIZE;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
@ -71,9 +75,9 @@ public final class NDocumentInputStream extends DocumentInputStream {
_document_size = document.getSize(); _document_size = document.getSize();
_closed = false; _closed = false;
if (_document_size < 0) { // can't be asserted ... see bug 61300
//throw new RecordFormatException("Document size can't be < 0"); // assert (_document_size >= 0) : "Document size can't be < 0";
}
DocumentNode doc = (DocumentNode)document; DocumentNode doc = (DocumentNode)document;
DocumentProperty property = (DocumentProperty)doc.getProperty(); DocumentProperty property = (DocumentProperty)doc.getProperty();
_document = new NPOIFSDocument( _document = new NPOIFSDocument(
@ -284,33 +288,33 @@ public final class NDocumentInputStream extends DocumentInputStream {
@Override @Override
public long readLong() { public long readLong() {
checkAvaliable(SIZE_LONG); checkAvaliable(LONG_SIZE);
byte[] data = new byte[SIZE_LONG]; byte[] data = new byte[LONG_SIZE];
readFully(data, 0, SIZE_LONG); readFully(data, 0, LONG_SIZE);
return LittleEndian.getLong(data, 0); return LittleEndian.getLong(data, 0);
} }
@Override @Override
public short readShort() { public short readShort() {
checkAvaliable(SIZE_SHORT); checkAvaliable(SHORT_SIZE);
byte[] data = new byte[SIZE_SHORT]; byte[] data = new byte[SHORT_SIZE];
readFully(data, 0, SIZE_SHORT); readFully(data, 0, SHORT_SIZE);
return LittleEndian.getShort(data); return LittleEndian.getShort(data);
} }
@Override @Override
public int readInt() { public int readInt() {
checkAvaliable(SIZE_INT); checkAvaliable(INT_SIZE);
byte[] data = new byte[SIZE_INT]; byte[] data = new byte[INT_SIZE];
readFully(data, 0, SIZE_INT); readFully(data, 0, INT_SIZE);
return LittleEndian.getInt(data); return LittleEndian.getInt(data);
} }
@Override @Override
public int readUShort() { public int readUShort() {
checkAvaliable(SIZE_SHORT); checkAvaliable(SHORT_SIZE);
byte[] data = new byte[SIZE_SHORT]; byte[] data = new byte[SHORT_SIZE];
readFully(data, 0, SIZE_SHORT); readFully(data, 0, SHORT_SIZE);
return LittleEndian.getUShort(data); return LittleEndian.getUShort(data);
} }

View File

@ -17,6 +17,8 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static java.util.Collections.emptyList;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -25,7 +27,6 @@ import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable; import org.apache.poi.poifs.dev.POIFSViewable;
@ -37,7 +38,7 @@ import org.apache.poi.util.IOUtils;
* This class manages a document in the NIO POIFS filesystem. * This class manages a document in the NIO POIFS filesystem.
* This is the {@link NPOIFSFileSystem} version. * This is the {@link NPOIFSFileSystem} version.
*/ */
public final class NPOIFSDocument implements POIFSViewable { public final class NPOIFSDocument implements POIFSViewable, Iterable<ByteBuffer> {
//arbitrarily selected; may need to increase //arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000; private static final int MAX_RECORD_LENGTH = 100_000;
@ -51,7 +52,7 @@ public final class NPOIFSDocument implements POIFSViewable {
/** /**
* Constructor for an existing Document * Constructor for an existing Document
*/ */
public NPOIFSDocument(DocumentNode document) throws IOException { public NPOIFSDocument(DocumentNode document) {
this((DocumentProperty)document.getProperty(), this((DocumentProperty)document.getProperty(),
((DirectoryNode)document.getParent()).getNFileSystem()); ((DirectoryNode)document.getParent()).getNFileSystem());
} }
@ -59,9 +60,7 @@ public final class NPOIFSDocument implements POIFSViewable {
/** /**
* Constructor for an existing Document * Constructor for an existing Document
*/ */
public NPOIFSDocument(DocumentProperty property, NPOIFSFileSystem filesystem) public NPOIFSDocument(DocumentProperty property, NPOIFSFileSystem filesystem) {
throws IOException
{
this._property = property; this._property = property;
this._filesystem = filesystem; this._filesystem = filesystem;
@ -90,7 +89,8 @@ public final class NPOIFSDocument implements POIFSViewable {
// Build the property for it // Build the property for it
this._property = new DocumentProperty(name, length); this._property = new DocumentProperty(name, length);
_property.setStartBlock(_stream.getStartBlock()); _property.setStartBlock(_stream.getStartBlock());
_property.setDocument(this);
} }
public NPOIFSDocument(String name, int size, NPOIFSFileSystem filesystem, POIFSWriterListener writer) public NPOIFSDocument(String name, int size, NPOIFSFileSystem filesystem, POIFSWriterListener writer)
@ -116,7 +116,8 @@ public final class NPOIFSDocument implements POIFSViewable {
// And build the property for it // And build the property for it
this._property = new DocumentProperty(name, size); this._property = new DocumentProperty(name, size);
_property.setStartBlock(_stream.getStartBlock()); _property.setStartBlock(_stream.getStartBlock());
_property.setDocument(this);
} }
/** /**
@ -128,7 +129,8 @@ public final class NPOIFSDocument implements POIFSViewable {
bis.mark(bigBlockSize); bis.mark(bigBlockSize);
// Do we need to store as a mini stream or a full one? // Do we need to store as a mini stream or a full one?
if(bis.skip(bigBlockSize) < bigBlockSize) { long streamBlockSize = IOUtils.skipFully(bis, bigBlockSize);
if (streamBlockSize < bigBlockSize) {
_stream = new NPOIFSStream(_filesystem.getMiniStore()); _stream = new NPOIFSStream(_filesystem.getMiniStore());
_block_size = _filesystem.getMiniStore().getBlockStoreBlockSize(); _block_size = _filesystem.getMiniStore().getBlockStoreBlockSize();
} else { } else {
@ -140,26 +142,21 @@ public final class NPOIFSDocument implements POIFSViewable {
bis.reset(); bis.reset();
// Store it // Store it
OutputStream os = _stream.getOutputStream(); final long length;
byte buf[] = new byte[1024]; try (OutputStream os = _stream.getOutputStream()) {
int length = 0; length = IOUtils.copy(bis, os);
for (int readBytes; (readBytes = bis.read(buf)) != -1; length += readBytes) { // Pad to the end of the block with -1s
os.write(buf, 0, readBytes); int usedInBlock = (int) (length % _block_size);
if (usedInBlock != 0 && usedInBlock != _block_size) {
int toBlockEnd = _block_size - usedInBlock;
byte[] padding = IOUtils.safelyAllocate(toBlockEnd, MAX_RECORD_LENGTH);
Arrays.fill(padding, (byte) 0xFF);
os.write(padding);
}
} }
// Pad to the end of the block with -1s return (int)length;
int usedInBlock = length % _block_size;
if (usedInBlock != 0 && usedInBlock != _block_size) {
int toBlockEnd = _block_size - usedInBlock;
byte[] padding = IOUtils.safelyAllocate(toBlockEnd, MAX_RECORD_LENGTH);
Arrays.fill(padding, (byte)0xFF);
os.write(padding);
}
// Tidy and return the length
os.close();
return length;
} }
/** /**
@ -178,15 +175,15 @@ public final class NPOIFSDocument implements POIFSViewable {
int getDocumentBlockSize() { int getDocumentBlockSize() {
return _block_size; return _block_size;
} }
Iterator<ByteBuffer> getBlockIterator() { @Override
if(getSize() > 0) { public Iterator<ByteBuffer> iterator() {
return _stream.getBlockIterator(); return getBlockIterator();
} else { }
List<ByteBuffer> empty = Collections.emptyList();
return empty.iterator(); Iterator<ByteBuffer> getBlockIterator() {
} return (getSize() > 0 ? _stream : Collections.<ByteBuffer>emptyList()).iterator();
} }
/** /**
* @return size of the document * @return size of the document
@ -240,7 +237,7 @@ public final class NPOIFSDocument implements POIFSViewable {
* store * store
*/ */
public Iterator<Object> getViewableIterator() { public Iterator<Object> getViewableIterator() {
return Collections.emptyList().iterator(); return emptyList().iterator();
} }
/** /**
@ -261,10 +258,7 @@ public final class NPOIFSDocument implements POIFSViewable {
* @return short description * @return short description
*/ */
public String getShortDescription() { public String getShortDescription() {
StringBuffer buffer = new StringBuffer();
buffer.append("Document: \"").append(_property.getName()).append("\""); return "Document: \"" + _property.getName() + "\" size = " + getSize();
buffer.append(" size = ").append(getSize());
return buffer.toString();
} }
} }

View File

@ -1,341 +0,0 @@
/* ====================================================================
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.poifs.filesystem;
import java.io.IOException;
import java.util.function.Function;
import org.apache.poi.poifs.storage.DataInputBlock;
import org.apache.poi.util.RecordFormatException;
/**
* This class provides methods to read a DocumentEntry managed by a
* {@link OPOIFSFileSystem} instance.
*/
public final class ODocumentInputStream extends DocumentInputStream {
/** current offset into the Document */
private int _current_offset;
/** current marked offset into the Document (used by mark and reset) */
private int _marked_offset;
/** the Document's size */
private final int _document_size;
/** have we been closed? */
private boolean _closed;
/** the actual Document */
private final OPOIFSDocument _document;
/** the data block containing the current stream pointer */
private DataInputBlock _currentBlock;
/**
* Create an InputStream from the specified DocumentEntry
*
* @param document the DocumentEntry to be read
*
* @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
* been deleted?)
*/
public ODocumentInputStream(DocumentEntry document) throws IOException {
if (!(document instanceof DocumentNode)) {
throw new IOException("Cannot open internal document storage");
}
DocumentNode documentNode = (DocumentNode)document;
if (documentNode.getDocument() == null) {
throw new IOException("Cannot open internal document storage");
}
_current_offset = 0;
_marked_offset = 0;
_document_size = document.getSize();
if (_document_size < 0) {
throw new RecordFormatException("document_size cannot be < 0");
}
_closed = false;
_document = documentNode.getDocument();
_currentBlock = getDataInputBlock(0);
}
/**
* Create an InputStream from the specified Document
*
* @param document the Document to be read
*/
public ODocumentInputStream(OPOIFSDocument document) {
_current_offset = 0;
_marked_offset = 0;
_document_size = document.getSize();
_closed = false;
_document = document;
_currentBlock = getDataInputBlock(0);
}
@Override
public int available() {
if (_closed) {
throw new IllegalStateException("cannot perform requested operation on a closed stream");
}
return _document_size - _current_offset;
}
@Override
public void close() {
_closed = true;
}
@Override
public void mark(int ignoredReadlimit) {
_marked_offset = _current_offset;
}
private DataInputBlock getDataInputBlock(int offset) {
return _document.getDataInputBlock(offset);
}
@Override
public int read() throws IOException {
dieIfClosed();
if (atEOD()) {
return EOF;
}
int result = _currentBlock.readUByte();
_current_offset++;
if (_currentBlock.available() < 1) {
_currentBlock = getDataInputBlock(_current_offset);
}
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
dieIfClosed();
if (b == null) {
throw new IllegalArgumentException("buffer must not be null");
}
if (off < 0 || len < 0 || b.length < off + len) {
throw new IndexOutOfBoundsException("can't read past buffer boundaries");
}
if (len == 0) {
return 0;
}
if (atEOD()) {
return EOF;
}
int limit = Math.min(_document_size - _current_offset, len);
readFully(b, off, limit);
return limit;
}
/**
* Repositions this stream to the position at the time the mark() method was
* last called on this input stream. If mark() has not been called this
* method repositions the stream to its beginning.
*/
@Override
public void reset() {
_current_offset = _marked_offset;
_currentBlock = getDataInputBlock(_current_offset);
}
@Override
public long skip(long n) throws IOException {
dieIfClosed();
if (n < 0) {
return 0;
}
int new_offset = _current_offset + (int) n;
if (new_offset < _current_offset) {
// wrap around in converting a VERY large long to an int
new_offset = _document_size;
} else if (new_offset > _document_size) {
new_offset = _document_size;
}
long rval = new_offset - _current_offset;
_current_offset = new_offset;
_currentBlock = getDataInputBlock(_current_offset);
return rval;
}
private void dieIfClosed() throws IOException {
if (_closed) {
throw new IOException("cannot perform requested operation on a closed stream");
}
}
private boolean atEOD() {
return _current_offset == _document_size;
}
private void checkAvaliable(int requestedSize) {
if (_closed) {
throw new IllegalStateException("cannot perform requested operation on a closed stream");
}
if (requestedSize > _document_size - _current_offset) {
throw new RuntimeException("Buffer underrun - requested " + requestedSize
+ " bytes but " + (_document_size - _current_offset) + " was available");
}
}
@Override
public byte readByte() {
return (byte) readUByte();
}
@Override
public double readDouble() {
return Double.longBitsToDouble(readLong());
}
@Override
public short readShort() {
return (short) readUShort();
}
@Override
public void readFully(byte[] buf, int off, int len) {
checkAvaliable(len);
Function<Integer,DataInputBlock> nextDataInputBlock = (offset) -> {
if (offset >= _document_size) {
_currentBlock = null;
} else if (offset != _current_offset) {
_currentBlock = getDataInputBlock(offset);
}
return _currentBlock;
};
_current_offset = readFullyInternal(buf, off, len, _current_offset, _document_size, nextDataInputBlock);
}
/* package */ static int readFullyInternal(byte[] buf, int off, int len, int currentOffset, int maxSize, Function<Integer,DataInputBlock> nextDataInputBlock) {
DataInputBlock currentBlock = nextDataInputBlock.apply(currentOffset);
if (currentBlock == null) {
throw new IllegalStateException("reached end of document stream unexpectedly");
}
int blockAvailable = currentBlock.available();
if (blockAvailable > len) {
currentBlock.readFully(buf, off, len);
return currentOffset + len;
}
// else read big amount in chunks
int remaining = len;
int writePos = off;
int offset = currentOffset;
while (remaining > 0) {
final boolean blockIsExpiring = remaining >= blockAvailable;
final int reqSize = (blockIsExpiring) ? blockAvailable : remaining;
currentBlock.readFully(buf, writePos, reqSize);
remaining -= reqSize;
writePos += reqSize;
offset += reqSize;
if (blockIsExpiring) {
if (offset >= maxSize) {
if (remaining > 0) {
throw new IllegalStateException(
"reached end of document stream unexpectedly");
}
break;
}
currentBlock = nextDataInputBlock.apply(offset);
if (currentBlock == null) {
throw new IllegalStateException(
"reached end of document stream unexpectedly");
}
blockAvailable = currentBlock.available();
}
}
return offset;
}
@Override
public long readLong() {
checkAvaliable(SIZE_LONG);
int blockAvailable = _currentBlock.available();
long result;
if (blockAvailable > SIZE_LONG) {
result = _currentBlock.readLongLE();
} else {
DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
if (blockAvailable == SIZE_LONG) {
result = _currentBlock.readLongLE();
} else {
result = nextBlock.readLongLE(_currentBlock, blockAvailable);
}
_currentBlock = nextBlock;
}
_current_offset += SIZE_LONG;
return result;
}
@Override
public int readInt() {
checkAvaliable(SIZE_INT);
int blockAvailable = _currentBlock.available();
int result;
if (blockAvailable > SIZE_INT) {
result = _currentBlock.readIntLE();
} else {
DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
if (blockAvailable == SIZE_INT) {
result = _currentBlock.readIntLE();
} else {
result = nextBlock.readIntLE(_currentBlock, blockAvailable);
}
_currentBlock = nextBlock;
}
_current_offset += SIZE_INT;
return result;
}
@Override
public int readUShort() {
checkAvaliable(SIZE_SHORT);
int blockAvailable = _currentBlock.available();
int result;
if (blockAvailable > SIZE_SHORT) {
result = _currentBlock.readUShortLE();
} else {
DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
if (blockAvailable == SIZE_SHORT) {
result = _currentBlock.readUShortLE();
} else {
result = nextBlock.readUShortLE(_currentBlock);
}
_currentBlock = nextBlock;
}
_current_offset += SIZE_SHORT;
return result;
}
@Override
public int readUByte() {
checkAvaliable(1);
int result = _currentBlock.readUByte();
_current_offset++;
if (_currentBlock.available() < 1) {
_currentBlock = getDataInputBlock(_current_offset);
}
return result;
}
}

View File

@ -1,516 +0,0 @@
/* ====================================================================
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.poifs.filesystem;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DocumentProperty;
import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.storage.BlockWritable;
import org.apache.poi.poifs.storage.DataInputBlock;
import org.apache.poi.poifs.storage.DocumentBlock;
import org.apache.poi.poifs.storage.ListManagedBlock;
import org.apache.poi.poifs.storage.RawDataBlock;
import org.apache.poi.poifs.storage.SmallDocumentBlock;
import org.apache.poi.util.HexDump;
/**
* This class manages a document in a old-style
* OPOIFS filesystem.
*/
public final class OPOIFSDocument implements BATManaged, BlockWritable, POIFSViewable {
private static final DocumentBlock[] EMPTY_BIG_BLOCK_ARRAY = { };
private static final SmallDocumentBlock[] EMPTY_SMALL_BLOCK_ARRAY = { };
private DocumentProperty _property;
private int _size;
private final POIFSBigBlockSize _bigBigBlockSize;
// one of these stores will be valid
private SmallBlockStore _small_store;
private BigBlockStore _big_store;
/**
* Constructor from large blocks
*
* @param name the name of the POIFSDocument
* @param blocks the big blocks making up the POIFSDocument
* @param length the actual length of the POIFSDocument
*/
public OPOIFSDocument(String name, RawDataBlock[] blocks, int length) throws IOException {
_size = length;
if(blocks.length == 0) {
_bigBigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;
} else {
_bigBigBlockSize = (blocks[0].getBigBlockSize() == POIFSConstants.SMALLER_BIG_BLOCK_SIZE ?
POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS :
POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS
);
}
_big_store = new BigBlockStore(_bigBigBlockSize, convertRawBlocksToBigBlocks(blocks));
_property = new DocumentProperty(name, _size);
_small_store = new SmallBlockStore(_bigBigBlockSize, EMPTY_SMALL_BLOCK_ARRAY);
_property.setDocument(this);
}
// TODO - awkward typing going on here
private static DocumentBlock[] convertRawBlocksToBigBlocks(ListManagedBlock[] blocks) throws IOException {
DocumentBlock[] result = new DocumentBlock[blocks.length];
for (int i = 0; i < result.length; i++) {
result[i] = new DocumentBlock((RawDataBlock)blocks[i]);
}
return result;
}
private static SmallDocumentBlock[] convertRawBlocksToSmallBlocks(ListManagedBlock[] blocks) {
if (blocks instanceof SmallDocumentBlock[]) {
return (SmallDocumentBlock[]) blocks;
}
SmallDocumentBlock[] result = new SmallDocumentBlock[blocks.length];
System.arraycopy(blocks, 0, result, 0, blocks.length);
return result;
}
/**
* Constructor from small blocks
*
* @param name the name of the POIFSDocument
* @param blocks the small blocks making up the POIFSDocument
* @param length the actual length of the POIFSDocument
*/
public OPOIFSDocument(String name, SmallDocumentBlock[] blocks, int length) {
_size = length;
if(blocks.length == 0) {
_bigBigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;
} else {
_bigBigBlockSize = blocks[0].getBigBlockSize();
}
_big_store = new BigBlockStore(_bigBigBlockSize, EMPTY_BIG_BLOCK_ARRAY);
_property = new DocumentProperty(name, _size);
_small_store = new SmallBlockStore(_bigBigBlockSize, blocks);
_property.setDocument(this);
}
/**
* Constructor from small blocks
*
* @param name the name of the POIFSDocument
* @param blocks the small blocks making up the POIFSDocument
* @param length the actual length of the POIFSDocument
*/
public OPOIFSDocument(String name, POIFSBigBlockSize bigBlockSize, ListManagedBlock[] blocks, int length) throws IOException {
_size = length;
_bigBigBlockSize = bigBlockSize;
_property = new DocumentProperty(name, _size);
_property.setDocument(this);
if (Property.isSmall(_size)) {
_big_store = new BigBlockStore(bigBlockSize,EMPTY_BIG_BLOCK_ARRAY);
_small_store = new SmallBlockStore(bigBlockSize,convertRawBlocksToSmallBlocks(blocks));
} else {
_big_store = new BigBlockStore(bigBlockSize,convertRawBlocksToBigBlocks(blocks));
_small_store = new SmallBlockStore(bigBlockSize,EMPTY_SMALL_BLOCK_ARRAY);
}
}
public OPOIFSDocument(String name, ListManagedBlock[] blocks, int length) throws IOException {
this(name, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, blocks, length);
}
/**
* Constructor
*
* @param name the name of the POIFSDocument
* @param stream the InputStream we read data from
*/
public OPOIFSDocument(String name, POIFSBigBlockSize bigBlockSize, InputStream stream) throws IOException {
List<DocumentBlock> blocks = new ArrayList<>();
_size = 0;
_bigBigBlockSize = bigBlockSize;
while (true) {
DocumentBlock block = new DocumentBlock(stream, bigBlockSize);
int blockSize = block.size();
if (blockSize > 0) {
blocks.add(block);
_size += blockSize;
}
if (block.partiallyRead()) {
break;
}
}
DocumentBlock[] bigBlocks = blocks.toArray(new DocumentBlock[blocks.size()]);
_big_store = new BigBlockStore(bigBlockSize,bigBlocks);
_property = new DocumentProperty(name, _size);
_property.setDocument(this);
if (_property.shouldUseSmallBlocks()) {
_small_store = new SmallBlockStore(bigBlockSize,SmallDocumentBlock.convert(bigBlockSize,bigBlocks, _size));
_big_store = new BigBlockStore(bigBlockSize,new DocumentBlock[0]);
} else {
_small_store = new SmallBlockStore(bigBlockSize,EMPTY_SMALL_BLOCK_ARRAY);
}
}
public OPOIFSDocument(String name, InputStream stream) throws IOException {
this(name, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, stream);
}
/**
* Constructor
*
* @param name the name of the POIFSDocument
* @param size the length of the POIFSDocument
* @param path the path of the POIFSDocument
* @param writer the writer who will eventually write the document contents
*/
public OPOIFSDocument(String name, int size, POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path, POIFSWriterListener writer) {
_size = size;
_bigBigBlockSize = bigBlockSize;
_property = new DocumentProperty(name, _size);
_property.setDocument(this);
if (_property.shouldUseSmallBlocks()) {
_small_store = new SmallBlockStore(_bigBigBlockSize, path, name, size, writer);
_big_store = new BigBlockStore(_bigBigBlockSize, EMPTY_BIG_BLOCK_ARRAY);
} else {
_small_store = new SmallBlockStore(_bigBigBlockSize, EMPTY_SMALL_BLOCK_ARRAY);
_big_store = new BigBlockStore(_bigBigBlockSize, path, name, size, writer);
}
}
public OPOIFSDocument(String name, int size, POIFSDocumentPath path, POIFSWriterListener writer) {
this(name, size, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, path, writer);
}
/**
* @return array of SmallDocumentBlocks; may be empty, cannot be null
*/
public SmallDocumentBlock[] getSmallBlocks() {
return _small_store.getBlocks();
}
/**
* @return size of the document
*/
public int getSize() {
return _size;
}
/**
* read data from the internal stores
*
* @param buffer the buffer to write to
* @param offset the offset into our storage to read from
* This method is currently (Oct 2008) only used by test code. Perhaps it can be deleted
*/
void read(byte[] buffer, int offset) {
ODocumentInputStream.readFullyInternal(buffer, 0, buffer.length, offset, _size, this::getDataInputBlock);
}
/**
* @return <code>null</code> if <tt>offset</tt> points to the end of the document stream
*/
DataInputBlock getDataInputBlock(int offset) {
if (offset >= _size) {
if (offset > _size) {
throw new RuntimeException("Request for Offset " + offset + " doc size is " + _size);
}
return null;
}
if (_property.shouldUseSmallBlocks()) {
return SmallDocumentBlock.getDataInputBlock(_small_store.getBlocks(), offset);
}
return DocumentBlock.getDataInputBlock(_big_store.getBlocks(), offset);
}
/**
* @return the instance's DocumentProperty
*/
DocumentProperty getDocumentProperty() {
return _property;
}
/* ********** START implementation of BlockWritable ********** */
/**
* Write the storage to an OutputStream
*
* @param stream the OutputStream to which the stored data should be written
*/
public void writeBlocks(OutputStream stream) throws IOException {
_big_store.writeBlocks(stream);
}
/* ********** END implementation of BlockWritable ********** */
/* ********** START implementation of BATManaged ********** */
/**
* Return the number of BigBlock's this instance uses
*
* @return count of BigBlock instances
*/
public int countBlocks() {
return _big_store.countBlocks();
}
/**
* Set the start block for this instance
*
* @param index index into the array of blocks making up the filesystem
*/
public void setStartBlock(int index) {
_property.setStartBlock(index);
}
/* ********** END implementation of BATManaged ********** */
/* ********** START begin implementation of POIFSViewable ********** */
/**
* Get an array of objects, some of which may implement POIFSViewable
*
* @return an array of Object; may not be null, but may be empty
*/
public Object[] getViewableArray() {
String result = "<NO DATA>";
try {
BlockWritable[] blocks = null;
if (_big_store.isValid()) {
blocks = _big_store.getBlocks();
} else if (_small_store.isValid()) {
blocks = _small_store.getBlocks();
}
if (blocks != null) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
for (BlockWritable bw : blocks) {
bw.writeBlocks(output);
}
int length = Math.min(output.size(), _property.getSize());
result = HexDump.dump(output.toByteArray(), 0, 0, length);
}
} catch (IOException e) {
result = e.getMessage();
}
return new String[]{ result };
}
/**
* Get an Iterator of objects, some of which may implement POIFSViewable
*
* @return an Iterator; may not be null, but may have an empty back end
* store
*/
public Iterator<Object> getViewableIterator() {
return Collections.emptyList().iterator();
}
/**
* Give viewers a hint as to whether to call getViewableArray or
* getViewableIterator
*
* @return <code>true</code> if a viewer should call getViewableArray,
* <code>false</code> if a viewer should call getViewableIterator
*/
public boolean preferArray() {
return true;
}
/**
* Provides a short description of the object, to be used when a
* POIFSViewable object has not provided its contents.
*
* @return short description
*/
public String getShortDescription() {
return "Document: \"" + _property.getName() + "\"" +
" size = " + getSize();
}
/* ********** END begin implementation of POIFSViewable ********** */
private static final class SmallBlockStore {
private SmallDocumentBlock[] _smallBlocks;
private final POIFSDocumentPath _path;
private final String _name;
private final int _size;
private final POIFSWriterListener _writer;
private final POIFSBigBlockSize _bigBlockSize;
/**
* Constructor
*
* @param blocks blocks to construct the store from
*/
SmallBlockStore(POIFSBigBlockSize bigBlockSize, SmallDocumentBlock[] blocks) {
_bigBlockSize = bigBlockSize;
_smallBlocks = blocks.clone();
this._path = null;
this._name = null;
this._size = -1;
this._writer = null;
}
/**
* Constructor for a small block store that will be written later
*
* @param path path of the document
* @param name name of the document
* @param size length of the document
* @param writer the object that will eventually write the document
*/
SmallBlockStore(POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path,
String name, int size, POIFSWriterListener writer) {
_bigBlockSize = bigBlockSize;
_smallBlocks = new SmallDocumentBlock[0];
this._path = path;
this._name = name;
this._size = size;
this._writer = writer;
}
/**
* @return <code>true</code> if this store is a valid source of data
*/
boolean isValid() {
return _smallBlocks.length > 0 || _writer != null;
}
/**
* @return the SmallDocumentBlocks
*/
SmallDocumentBlock[] getBlocks() {
if (isValid() && _writer != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream(_size);
DocumentOutputStream dstream = new DocumentOutputStream(stream, _size);
_writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, _path, _name, _size));
_smallBlocks = SmallDocumentBlock.convert(_bigBlockSize, stream.toByteArray(), _size);
}
return _smallBlocks;
}
} // end private class SmallBlockStore
private static final class BigBlockStore {
private DocumentBlock[] bigBlocks;
private final POIFSDocumentPath _path;
private final String _name;
private final int _size;
private final POIFSWriterListener _writer;
private final POIFSBigBlockSize _bigBlockSize;
/**
* Constructor
*
* @param blocks the blocks making up the store
*/
BigBlockStore(POIFSBigBlockSize bigBlockSize, DocumentBlock[] blocks) {
_bigBlockSize = bigBlockSize;
bigBlocks = blocks.clone();
_path = null;
_name = null;
_size = -1;
_writer = null;
}
/**
* Constructor for a big block store that will be written later
*
* @param path path of the document
* @param name name of the document
* @param size length of the document
* @param writer the object that will eventually write the document
*/
BigBlockStore(POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path,
String name, int size, POIFSWriterListener writer) {
_bigBlockSize = bigBlockSize;
bigBlocks = new DocumentBlock[0];
_path = path;
_name = name;
_size = size;
_writer = writer;
}
/**
* @return <code>true</code> if this store is a valid source of data
*/
boolean isValid() {
return bigBlocks.length > 0 || _writer != null;
}
/**
* @return the DocumentBlocks
*/
DocumentBlock[] getBlocks() {
if (isValid() && _writer != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream(_size);
DocumentOutputStream dstream = new DocumentOutputStream(stream, _size);
_writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, _path, _name, _size));
bigBlocks = DocumentBlock.convert(_bigBlockSize, stream.toByteArray(), _size);
}
return bigBlocks;
}
/**
* write the blocks to a stream
*
* @param stream the stream to which the data is to be written
*/
void writeBlocks(OutputStream stream) throws IOException {
if (isValid()) {
if (_writer != null) {
DocumentOutputStream dstream = new DocumentOutputStream(stream, _size);
_writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, _path, _name, _size));
dstream.writeFiller(countBlocks() * _bigBlockSize.getBigBlockSize(),
DocumentBlock.getFillByte());
} else {
for (DocumentBlock bigBlock : bigBlocks) {
bigBlock.writeBlocks(stream);
}
}
}
}
/**
* @return number of big blocks making up this document
*/
int countBlocks() {
if (isValid()) {
if (_writer == null) {
return bigBlocks.length;
}
return (_size + _bigBlockSize.getBigBlockSize() - 1)
/ _bigBlockSize.getBigBlockSize();
}
return 0;
}
} // end private class BigBlockStore
}

View File

@ -1,570 +0,0 @@
/* ====================================================================
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.poifs.filesystem;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.storage.BATBlock;
import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.BlockAllocationTableWriter;
import org.apache.poi.poifs.storage.BlockList;
import org.apache.poi.poifs.storage.BlockWritable;
import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.HeaderBlockWriter;
import org.apache.poi.poifs.storage.RawDataBlockList;
import org.apache.poi.poifs.storage.SmallBlockTableReader;
import org.apache.poi.poifs.storage.SmallBlockTableWriter;
import org.apache.poi.util.CloseIgnoringInputStream;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* <p>This is the main class of the POIFS system; it manages the entire
* life cycle of the filesystem.</p>
* <p>This is the older version, which uses more memory, and doesn't
* support in-place writes.</p>
*/
public class OPOIFSFileSystem
implements POIFSViewable
{
private static final POILogger _logger =
POILogFactory.getLogger(OPOIFSFileSystem.class);
/**
* Convenience method for clients that want to avoid the auto-close behaviour of the constructor.
*/
public static InputStream createNonClosingInputStream(InputStream is) {
return new CloseIgnoringInputStream(is);
}
private PropertyTable _property_table;
private List<OPOIFSDocument> _documents;
private DirectoryNode _root;
/**
* What big block size the file uses. Most files
* use 512 bytes, but a few use 4096
*/
private POIFSBigBlockSize bigBlockSize =
POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;
/**
* Constructor, intended for writing
*/
public OPOIFSFileSystem()
{
HeaderBlock header_block = new HeaderBlock(bigBlockSize);
_property_table = new PropertyTable(header_block);
_documents = new ArrayList<>();
_root = null;
}
/**
* Create a OPOIFSFileSystem from an <tt>InputStream</tt>. Normally the stream is read until
* EOF. The stream is always closed.<p>
*
* Some streams are usable after reaching EOF (typically those that return <code>true</code>
* for <tt>markSupported()</tt>). In the unlikely case that the caller has such a stream
* <i>and</i> needs to use it after this constructor completes, a work around is to wrap the
* stream in order to trap the <tt>close()</tt> call. A convenience method (
* <tt>createNonClosingInputStream()</tt>) has been provided for this purpose:
* <pre>
* InputStream wrappedStream = OPOIFSFileSystem.createNonClosingInputStream(is);
* HSSFWorkbook wb = new HSSFWorkbook(wrappedStream);
* is.reset();
* doSomethingElse(is);
* </pre>
* Note also the special case of <tt>ByteArrayInputStream</tt> for which the <tt>close()</tt>
* method does nothing.
* <pre>
* ByteArrayInputStream bais = ...
* HSSFWorkbook wb = new HSSFWorkbook(bais); // calls bais.close() !
* bais.reset(); // no problem
* doSomethingElse(bais);
* </pre>
*
* @param stream the InputStream from which to read the data
*
* @exception IOException on errors reading, or on invalid data
*/
public OPOIFSFileSystem(InputStream stream)
throws IOException
{
this();
boolean success = false;
HeaderBlock header_block;
RawDataBlockList data_blocks;
try {
// read the header block from the stream
header_block = new HeaderBlock(stream);
bigBlockSize = header_block.getBigBlockSize();
// read the rest of the stream into blocks
data_blocks = new RawDataBlockList(stream, bigBlockSize);
success = true;
} finally {
closeInputStream(stream, success);
}
// set up the block allocation table (necessary for the
// data_blocks to be manageable
new BlockAllocationTableReader(header_block.getBigBlockSize(),
header_block.getBATCount(),
header_block.getBATArray(),
header_block.getXBATCount(),
header_block.getXBATIndex(),
data_blocks);
// get property table from the document
PropertyTable properties =
new PropertyTable(header_block, data_blocks);
// init documents
processProperties(
SmallBlockTableReader.getSmallDocumentBlocks(
bigBlockSize, data_blocks, properties.getRoot(),
header_block.getSBATStart()
),
data_blocks,
properties.getRoot().getChildren(),
null,
header_block.getPropertyStart()
);
// For whatever reason CLSID of root is always 0.
getRoot().setStorageClsid(properties.getRoot().getStorageClsid());
}
/**
* @param stream the stream to be closed
* @param success <code>false</code> if an exception is currently being thrown in the calling method
*/
protected void closeInputStream(InputStream stream, boolean success) {
if(stream.markSupported() && !(stream instanceof ByteArrayInputStream)) {
String msg = "POIFS is closing the supplied input stream of type ("
+ stream.getClass().getName() + ") which supports mark/reset. "
+ "This will be a problem for the caller if the stream will still be used. "
+ "If that is the case the caller should wrap the input stream to avoid this close logic. "
+ "This warning is only temporary and will not be present in future versions of POI.";
_logger.log(POILogger.WARN, msg);
}
try {
stream.close();
} catch (IOException e) {
if(success) {
throw new RuntimeException(e);
}
// else not success? Try block did not complete normally
// just print stack trace and leave original ex to be thrown
_logger.log(POILogger.ERROR, "can't close input stream", e);
}
}
/**
* Create a new document to be added to the root directory
*
* @param stream the InputStream from which the document's data
* will be obtained
* @param name the name of the new POIFSDocument
*
* @return the new DocumentEntry
*
* @exception IOException on error creating the new POIFSDocument
*/
public DocumentEntry createDocument(final InputStream stream,
final String name)
throws IOException
{
return getRoot().createDocument(name, stream);
}
/**
* create a new DocumentEntry in the root entry; the data will be
* provided later
*
* @param name the name of the new DocumentEntry
* @param size the size of the new DocumentEntry
* @param writer the writer of the new DocumentEntry
*
* @return the new DocumentEntry
*
* @exception IOException
*/
public DocumentEntry createDocument(final String name, final int size,
final POIFSWriterListener writer)
throws IOException
{
return getRoot().createDocument(name, size, writer);
}
/**
* create a new DirectoryEntry in the root directory
*
* @param name the name of the new DirectoryEntry
*
* @return the new DirectoryEntry
*
* @exception IOException on name duplication
*/
public DirectoryEntry createDirectory(final String name)
throws IOException
{
return getRoot().createDirectory(name);
}
/**
* Write the filesystem out
*
* @param stream the OutputStream to which the filesystem will be
* written
*
* @exception IOException thrown on errors writing to the stream
*/
public void writeFilesystem(final OutputStream stream)
throws IOException
{
// get the property table ready
_property_table.preWrite();
// create the small block store, and the SBAT
SmallBlockTableWriter sbtw =
new SmallBlockTableWriter(bigBlockSize, _documents, _property_table.getRoot());
// create the block allocation table
BlockAllocationTableWriter bat =
new BlockAllocationTableWriter(bigBlockSize);
// create a list of BATManaged objects: the documents plus the
// property table and the small block table
List<Object> bm_objects = new ArrayList<>();
bm_objects.addAll(_documents);
bm_objects.add(_property_table);
bm_objects.add(sbtw);
bm_objects.add(sbtw.getSBAT());
// walk the list, allocating space for each and assigning each
// a starting block number
Iterator<Object> iter = bm_objects.iterator();
while (iter.hasNext())
{
BATManaged bmo = ( BATManaged ) iter.next();
int block_count = bmo.countBlocks();
if (block_count != 0) {
bmo.setStartBlock(bat.allocateSpace(block_count));
} /*else {
// Either the BATManaged object is empty or its data
// is composed of SmallBlocks; in either case,
// allocating space in the BAT is inappropriate
}*/
}
// allocate space for the block allocation table and take its
// starting block
int batStartBlock = bat.createBlocks();
// get the extended block allocation table blocks
HeaderBlockWriter header_block_writer = new HeaderBlockWriter(bigBlockSize);
BATBlock[] xbat_blocks =
header_block_writer.setBATBlocks(bat.countBlocks(),
batStartBlock);
// set the property table start block
header_block_writer.setPropertyStart(_property_table.getStartBlock());
// set the small block allocation table start block
header_block_writer.setSBATStart(sbtw.getSBAT().getStartBlock());
// set the small block allocation table block count
header_block_writer.setSBATBlockCount(sbtw.getSBATBlockCount());
// the header is now properly initialized. Make a list of
// writers (the header block, followed by the documents, the
// property table, the small block store, the small block
// allocation table, the block allocation table, and the
// extended block allocation table blocks)
List<Object> writers = new ArrayList<>();
writers.add(header_block_writer);
writers.addAll(_documents);
writers.add(_property_table);
writers.add(sbtw);
writers.add(sbtw.getSBAT());
writers.add(bat);
Collections.addAll(writers, xbat_blocks);
// now, write everything out
iter = writers.iterator();
while (iter.hasNext())
{
BlockWritable writer = ( BlockWritable ) iter.next();
writer.writeBlocks(stream);
}
}
/**
* read in a file and write it back out again
*
* @param args names of the files; arg[ 0 ] is the input file,
* arg[ 1 ] is the output file
*
* @exception IOException
*/
public static void main(String args[])
throws IOException
{
if (args.length != 2)
{
System.err.println(
"two arguments required: input filename and output filename");
System.exit(1);
}
FileInputStream istream = new FileInputStream(args[ 0 ]);
FileOutputStream ostream = new FileOutputStream(args[ 1 ]);
new OPOIFSFileSystem(istream).writeFilesystem(ostream);
istream.close();
ostream.close();
}
/**
* get the root entry
*
* @return the root entry
*/
public DirectoryNode getRoot()
{
if (_root == null)
{
_root = new DirectoryNode(_property_table.getRoot(), this, null);
}
return _root;
}
/**
* open a document in the root entry's list of entries
*
* @param documentName the name of the document to be opened
*
* @return a newly opened DocumentInputStream
*
* @exception IOException if the document does not exist or the
* name is that of a DirectoryEntry
*/
public DocumentInputStream createDocumentInputStream(
final String documentName)
throws IOException
{
return getRoot().createDocumentInputStream(documentName);
}
/**
* add a new POIFSDocument
*
* @param document the POIFSDocument being added
*/
void addDocument(final OPOIFSDocument document)
{
_documents.add(document);
_property_table.addProperty(document.getDocumentProperty());
}
/**
* add a new DirectoryProperty
*
* @param directory the DirectoryProperty being added
*/
void addDirectory(final DirectoryProperty directory)
{
_property_table.addProperty(directory);
}
/**
* remove an entry
*
* @param entry to be removed
*/
void remove(EntryNode entry)
{
_property_table.removeProperty(entry.getProperty());
if (entry.isDocumentEntry())
{
_documents.remove((( DocumentNode ) entry).getDocument());
}
}
private void processProperties(final BlockList small_blocks,
final BlockList big_blocks,
final Iterator<Property> properties,
final DirectoryNode dir,
final int headerPropertiesStartAt)
throws IOException
{
while (properties.hasNext())
{
Property property = properties.next();
String name = property.getName();
DirectoryNode parent = (dir == null)
? getRoot()
: dir;
if (property.isDirectory())
{
DirectoryNode new_dir =
( DirectoryNode ) parent.createDirectory(name);
new_dir.setStorageClsid( property.getStorageClsid() );
processProperties(
small_blocks, big_blocks,
(( DirectoryProperty ) property).getChildren(),
new_dir, headerPropertiesStartAt);
}
else
{
int startBlock = property.getStartBlock();
int size = property.getSize();
OPOIFSDocument document;
if (property.shouldUseSmallBlocks())
{
document =
new OPOIFSDocument(name,
small_blocks.fetchBlocks(startBlock, headerPropertiesStartAt),
size);
}
else
{
document =
new OPOIFSDocument(name,
big_blocks.fetchBlocks(startBlock, headerPropertiesStartAt),
size);
}
parent.createDocument(document);
}
}
}
/* ********** START begin implementation of POIFSViewable ********** */
/**
* Get an array of objects, some of which may implement
* POIFSViewable
*
* @return an array of Object; may not be null, but may be empty
*/
public Object [] getViewableArray()
{
if (preferArray())
{
return getRoot().getViewableArray();
}
return new Object[ 0 ];
}
/**
* Get an Iterator of objects, some of which may implement
* POIFSViewable
*
* @return an Iterator; may not be null, but may have an empty
* back end store
*/
public Iterator<Object> getViewableIterator()
{
if (!preferArray())
{
return getRoot().getViewableIterator();
}
return Collections.emptyList().iterator();
}
/**
* Give viewers a hint as to whether to call getViewableArray or
* getViewableIterator
*
* @return true if a viewer should call getViewableArray, false if
* a viewer should call getViewableIterator
*/
public boolean preferArray()
{
return getRoot().preferArray();
}
/**
* Provides a short description of the object, to be used when a
* POIFSViewable object has not provided its contents.
*
* @return short description
*/
public String getShortDescription()
{
return "POIFS FileSystem";
}
/**
* @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
*/
public int getBigBlockSize() {
return bigBlockSize.getBigBlockSize();
}
/**
* @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
*/
public POIFSBigBlockSize getBigBlockSizeDetails() {
return bigBlockSize;
}
/* ********** END begin implementation of POIFSViewable ********** */
} // end public class OPOIFSFileSystem

View File

@ -141,6 +141,6 @@ public class POIFSFileSystem
* arg[ 1 ] is the output file * arg[ 1 ] is the output file
*/ */
public static void main(String args[]) throws IOException { public static void main(String args[]) throws IOException {
OPOIFSFileSystem.main(args); NPOIFSFileSystem.main(args);
} }
} }

View File

@ -1,6 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> /* ====================================================================
<!--
====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership. this work for additional information regarding copyright ownership.
@ -15,22 +13,11 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== ==================================================================== */
-->
<html>
<head>
</head>
<body bgcolor="white">
storage package contains low level binary structures for POIFS's implementation of the OLE 2 /**
Compound Document Format. * filesystem package maps OLE 2 Compound document files to a more familiar filesystem interface.
*
<h2>Related Documentation</h2> * @see org.apache.poi.poifs.eventfilesystem
*/
For overviews, tutorials, examples, guides, and tool documentation, please see: package org.apache.poi.poifs.filesystem;
<ul>
<li><a href="http://poi.apache.org">Apache POI Project</a>
</ul>
</body>
</html>

View File

@ -1,37 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!--
====================================================================
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.
====================================================================
-->
<html>
<head>
</head>
<body bgcolor="white">
filesystem package maps OLE 2 Compound document files to a more familiar filesystem interface.
<h2>Related Documentation</h2>
For overviews, tutorials, examples, guides, and tool documentation, please see:
<ul>
<li><a href="http://poi.apache.org">Apache POI Project</a>
</ul>
<!-- Put @see and @since tags down here. -->
@see org.apache.poi.poifs.eventfilesystem
</body>
</html>

View File

@ -0,0 +1,25 @@
/* ====================================================================
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.
==================================================================== */
/**
* Poor Obfuscation Implementation FileSystem APIs implement the OLE 2 Compound Document format in
* pure Java. All POI subprojects are based upon this API.
*
* @see org.apache.poi.hssf
* @see org.apache.poi.hpsf
*/
package org.apache.poi.poifs;

View File

@ -1,39 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!--
====================================================================
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.
====================================================================
-->
<html>
<head>
</head>
<body bgcolor="white">
Poor Obfuscation Implementation FileSystem APIs implement the OLE 2 Compound Document format in
pure Java. All POI subprojects are based upon this API.
<h2>Related Documentation</h2>
For overviews, tutorials, examples, guides, and tool documentation, please see:
<ul>
<li><a href="http://poi.apache.org">Apache POI Project</a>
</ul>
<!-- Put @see and @since tags down here. -->
@see org.apache.poi.hssf
@see org.apache.poi.hpsf
</body>
</html>

View File

@ -30,7 +30,7 @@ import java.util.Set;
/** /**
* Directory property * Directory property
*/ */
public class DirectoryProperty extends Property implements Parent, Iterable<Property> { // TODO - fix instantiable superclass public class DirectoryProperty extends Property implements Parent, Iterable<Property> {
/** List of Property instances */ /** List of Property instances */
private List<Property> _children; private List<Property> _children;

View File

@ -19,14 +19,14 @@
package org.apache.poi.poifs.property; package org.apache.poi.poifs.property;
import org.apache.poi.poifs.filesystem.OPOIFSDocument; import org.apache.poi.poifs.filesystem.NPOIFSDocument;
/** /**
* Trivial extension of Property for POIFSDocuments * Trivial extension of Property for POIFSDocuments
*/ */
public class DocumentProperty extends Property { public class DocumentProperty extends Property {
// the POIFSDocument this property is associated with // the POIFSDocument this property is associated with
private OPOIFSDocument _document; private NPOIFSDocument _document;
/** /**
* Constructor * Constructor
@ -64,7 +64,7 @@ public class DocumentProperty extends Property {
* *
* @param doc the associated POIFSDocument * @param doc the associated POIFSDocument
*/ */
public void setDocument(OPOIFSDocument doc) public void setDocument(NPOIFSDocument doc)
{ {
_document = doc; _document = doc;
} }
@ -74,7 +74,7 @@ public class DocumentProperty extends Property {
* *
* @return the associated document * @return the associated document
*/ */
public OPOIFSDocument getDocument() public NPOIFSDocument getDocument()
{ {
return _document; return _document;
} }

View File

@ -18,7 +18,6 @@
package org.apache.poi.poifs.property; package org.apache.poi.poifs.property;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.storage.SmallDocumentBlock;
/** /**
* Root property * Root property
@ -43,9 +42,7 @@ public final class RootProperty extends DirectoryProperty {
* @param array byte data * @param array byte data
* @param offset offset into byte data * @param offset offset into byte data
*/ */
protected RootProperty(final int index, final byte [] array, RootProperty(final int index, final byte [] array, final int offset) {
final int offset)
{
super(index, array, offset); super(index, array, offset);
} }
@ -56,7 +53,9 @@ public final class RootProperty extends DirectoryProperty {
*/ */
public void setSize(int size) public void setSize(int size)
{ {
super.setSize(SmallDocumentBlock.calcSize(size)); final int BLOCK_SHIFT = 6;
final int _block_size = 1 << BLOCK_SHIFT;
super.setSize(size * _block_size);
} }
/** /**

View File

@ -0,0 +1,23 @@
/* ====================================================================
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.
==================================================================== */
/**
* property package contains high and low level Property structures for POIFS.
*
* @see org.apache.poi.poifs.filesystem
*/
package org.apache.poi.poifs.property;

View File

@ -1,37 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!--
====================================================================
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.
====================================================================
-->
<html>
<head>
</head>
<body bgcolor="white">
property package contains high and low level Property structures for POIFS.
<h2>Related Documentation</h2>
For overviews, tutorials, examples, guides, and tool documentation, please see:
<ul>
<li><a href="http://poi.apache.org">Apache POI Project</a>
</ul>
<!-- Put @see and @since tags down here. -->
@see org.apache.poi.poifs.filesystem
</body>
</html>

View File

@ -27,9 +27,9 @@ import org.apache.poi.util.LittleEndianConsts;
*/ */
public interface HeaderBlockConstants public interface HeaderBlockConstants
{ {
public static final long _signature = 0xE11AB1A1E011CFD0L; long _signature = 0xE11AB1A1E011CFD0L;
public static final int _bat_array_offset = 0x4c; int _bat_array_offset = 0x4c;
public static final int _max_bats_in_header = int _max_bats_in_header =
(POIFSConstants.SMALLER_BIG_BLOCK_SIZE - _bat_array_offset) (POIFSConstants.SMALLER_BIG_BLOCK_SIZE - _bat_array_offset)
/ LittleEndianConsts.INT_SIZE; // If 4k blocks, rest is blank / LittleEndianConsts.INT_SIZE; // If 4k blocks, rest is blank
@ -39,12 +39,12 @@ public interface HeaderBlockConstants
// XBAT ~= DIFat // XBAT ~= DIFat
// useful offsets // useful offsets
public static final int _signature_offset = 0; int _signature_offset = 0;
public static final int _bat_count_offset = 0x2C; int _bat_count_offset = 0x2C;
public static final int _property_start_offset = 0x30; int _property_start_offset = 0x30;
public static final int _sbat_start_offset = 0x3C; int _sbat_start_offset = 0x3C;
public static final int _sbat_block_count_offset = 0x40; int _sbat_block_count_offset = 0x40;
public static final int _xbat_start_offset = 0x44; int _xbat_start_offset = 0x44;
public static final int _xbat_count_offset = 0x48; int _xbat_count_offset = 0x48;
} // end public interface HeaderBlockConstants }

View File

@ -1,109 +0,0 @@
/* ====================================================================
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.poifs.storage;
import java.io.IOException;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.property.RootProperty;
/**
* This class implements reading the small document block list from an
* existing file
*/
public final class SmallBlockTableReader {
private static BlockList prepareSmallDocumentBlocks(
final POIFSBigBlockSize bigBlockSize,
final RawDataBlockList blockList, final RootProperty root,
final int sbatStart)
throws IOException
{
// Fetch the blocks which hold the Small Blocks stream
ListManagedBlock [] smallBlockBlocks =
blockList.fetchBlocks(root.getStartBlock(), -1);
// Turn that into a list
return new SmallDocumentBlockList(
SmallDocumentBlock.extract(bigBlockSize, smallBlockBlocks));
}
private static BlockAllocationTableReader prepareReader(
final POIFSBigBlockSize bigBlockSize,
final RawDataBlockList blockList, final BlockList list,
final RootProperty root, final int sbatStart)
throws IOException
{
// Process the SBAT and blocks
return new BlockAllocationTableReader(bigBlockSize,
blockList.fetchBlocks(sbatStart, -1),
list);
}
/**
* Fetch the small document block reader from an existing file, normally
* needed for debugging and low level dumping. You should typically call
* {@link #getSmallDocumentBlocks(POIFSBigBlockSize, RawDataBlockList, RootProperty, int)}
* instead.
*
* @param blockList the raw data from which the small block table
* will be extracted
* @param root the root property (which contains the start block
* and small block table size)
* @param sbatStart the start block of the SBAT
*
* @return the small document block reader
*
* @exception IOException
*/
public static BlockAllocationTableReader _getSmallDocumentBlockReader(
final POIFSBigBlockSize bigBlockSize,
final RawDataBlockList blockList, final RootProperty root,
final int sbatStart)
throws IOException
{
BlockList list = prepareSmallDocumentBlocks(
bigBlockSize, blockList, root, sbatStart);
return prepareReader(
bigBlockSize, blockList, list, root, sbatStart);
}
/**
* Fetch the small document block list from an existing file
*
* @param blockList the raw data from which the small block table
* will be extracted
* @param root the root property (which contains the start block
* and small block table size)
* @param sbatStart the start block of the SBAT
*
* @return the small document block list
*
* @exception IOException
*/
public static BlockList getSmallDocumentBlocks(
final POIFSBigBlockSize bigBlockSize,
final RawDataBlockList blockList, final RootProperty root,
final int sbatStart)
throws IOException
{
BlockList list = prepareSmallDocumentBlocks(
bigBlockSize, blockList, root, sbatStart);
prepareReader(bigBlockSize, blockList, list, root, sbatStart);
return list;
}
}

View File

@ -1,149 +0,0 @@
/* ====================================================================
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.poifs.storage;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.BATManaged;
import org.apache.poi.poifs.filesystem.OPOIFSDocument;
import org.apache.poi.poifs.property.RootProperty;
import java.util.*;
import java.io.*;
/**
* This class implements storage for writing the small blocks used by
* small documents.
*
* @author Marc Johnson (mjohnson at apache dot org)
*/
public class SmallBlockTableWriter
implements BlockWritable, BATManaged
{
private BlockAllocationTableWriter _sbat;
private List<SmallDocumentBlock> _small_blocks;
private int _big_block_count;
private RootProperty _root;
/**
* Creates new SmallBlockTable
*
* @param documents a List of POIFSDocument instances
* @param root the Filesystem's root property
*/
public SmallBlockTableWriter(final POIFSBigBlockSize bigBlockSize,
final List<OPOIFSDocument> documents,
final RootProperty root)
{
_sbat = new BlockAllocationTableWriter(bigBlockSize);
_small_blocks = new ArrayList<>();
_root = root;
for (OPOIFSDocument doc : documents)
{
SmallDocumentBlock[] blocks = doc.getSmallBlocks();
if (blocks.length != 0)
{
doc.setStartBlock(_sbat.allocateSpace(blocks.length));
for (int j = 0; j < blocks.length; j++)
{
_small_blocks.add(blocks[ j ]);
}
} else {
doc.setStartBlock(POIFSConstants.END_OF_CHAIN);
}
}
_sbat.simpleCreateBlocks();
_root.setSize(_small_blocks.size());
_big_block_count = SmallDocumentBlock.fill(bigBlockSize,_small_blocks);
}
/**
* Get the number of SBAT blocks
*
* @return number of SBAT big blocks
*/
public int getSBATBlockCount()
{
return (_big_block_count + 15) / 16;
}
/**
* Get the SBAT
*
* @return the Small Block Allocation Table
*/
public BlockAllocationTableWriter getSBAT()
{
return _sbat;
}
/* ********** START implementation of BATManaged ********** */
/**
* Return the number of BigBlock's this instance uses
*
* @return count of BigBlock instances
*/
public int countBlocks()
{
return _big_block_count;
}
/**
* Set the start block for this instance
*
* @param start_block
*/
public void setStartBlock(int start_block)
{
_root.setStartBlock(start_block);
}
/* ********** END implementation of BATManaged ********** */
/* ********** START implementation of BlockWritable ********** */
/**
* Write the storage to an OutputStream
*
* @param stream the OutputStream to which the stored data should
* be written
*
* @exception IOException on problems writing to the specified
* stream
*/
public void writeBlocks(final OutputStream stream)
throws IOException
{
for (BlockWritable block : _small_blocks) {
block.writeBlocks(stream);
}
}
/* ********** END implementation of BlockWritable ********** */
}

View File

@ -1,253 +0,0 @@
/* ====================================================================
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.poifs.storage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
/**
* Storage for documents that are too small to use regular
* DocumentBlocks for their data
*/
public final class SmallDocumentBlock implements BlockWritable, ListManagedBlock {
private static final int BLOCK_SHIFT = 6;
private byte[] _data;
private static final byte _default_fill = ( byte ) 0xff;
private static final int _block_size = 1 << BLOCK_SHIFT;
private static final int BLOCK_MASK = _block_size-1;
private final int _blocks_per_big_block;
private final POIFSBigBlockSize _bigBlockSize;
private SmallDocumentBlock(final POIFSBigBlockSize bigBlockSize, final byte [] data, final int index)
{
this(bigBlockSize);
System.arraycopy(data, index * _block_size, _data, 0, _block_size);
}
protected SmallDocumentBlock(final POIFSBigBlockSize bigBlockSize)
{
_bigBlockSize = bigBlockSize;
_blocks_per_big_block = getBlocksPerBigBlock(bigBlockSize);
_data = new byte[ _block_size ];
}
private static int getBlocksPerBigBlock(final POIFSBigBlockSize bigBlockSize)
{
return bigBlockSize.getBigBlockSize() / _block_size;
}
/**
* convert a single long array into an array of SmallDocumentBlock
* instances
*
* @param array the byte array to be converted
* @param size the intended size of the array (which may be smaller)
*
* @return an array of SmallDocumentBlock instances, filled from
* the array
*/
public static SmallDocumentBlock [] convert(POIFSBigBlockSize bigBlockSize,
byte [] array,
int size)
{
SmallDocumentBlock[] rval =
new SmallDocumentBlock[ (size + _block_size - 1) / _block_size ];
int offset = 0;
for (int k = 0; k < rval.length; k++)
{
rval[ k ] = new SmallDocumentBlock(bigBlockSize);
if (offset < array.length)
{
int length = Math.min(_block_size, array.length - offset);
System.arraycopy(array, offset, rval[ k ]._data, 0, length);
if (length != _block_size)
{
Arrays.fill(rval[ k ]._data, length, _block_size,
_default_fill);
}
}
else
{
Arrays.fill(rval[ k ]._data, _default_fill);
}
offset += _block_size;
}
return rval;
}
/**
* fill out a List of SmallDocumentBlocks so that it fully occupies
* a set of big blocks
*
* @param blocks the List to be filled out
*
* @return number of big blocks the list encompasses
*/
public static int fill(POIFSBigBlockSize bigBlockSize, List<SmallDocumentBlock> blocks)
{
int _blocks_per_big_block = getBlocksPerBigBlock(bigBlockSize);
int count = blocks.size();
int big_block_count = (count + _blocks_per_big_block - 1)
/ _blocks_per_big_block;
int full_count = big_block_count * _blocks_per_big_block;
for (; count < full_count; count++)
{
blocks.add(makeEmptySmallDocumentBlock(bigBlockSize));
}
return big_block_count;
}
/**
* Factory for creating SmallDocumentBlocks from DocumentBlocks
*
* @param store the original DocumentBlocks
* @param size the total document size
*
* @return an array of new SmallDocumentBlocks instances
*
* @exception IOException on errors reading from the DocumentBlocks
* @exception ArrayIndexOutOfBoundsException if, somehow, the store
* contains less data than size indicates
*/
public static SmallDocumentBlock [] convert(POIFSBigBlockSize bigBlockSize,
BlockWritable [] store,
int size)
throws IOException, ArrayIndexOutOfBoundsException
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
for (int j = 0; j < store.length; j++)
{
store[ j ].writeBlocks(stream);
}
byte[] data = stream.toByteArray();
SmallDocumentBlock[] rval =
new SmallDocumentBlock[ convertToBlockCount(size) ];
for (int index = 0; index < rval.length; index++)
{
rval[ index ] = new SmallDocumentBlock(bigBlockSize, data, index);
}
return rval;
}
/**
* create a list of SmallDocumentBlock's from raw data
*
* @param blocks the raw data containing the SmallDocumentBlock
* data
*
* @return a List of SmallDocumentBlock's extracted from the input
*/
public static List<SmallDocumentBlock> extract(POIFSBigBlockSize bigBlockSize, ListManagedBlock [] blocks)
throws IOException
{
int _blocks_per_big_block = getBlocksPerBigBlock(bigBlockSize);
List<SmallDocumentBlock> sdbs = new ArrayList<>();
for (int j = 0; j < blocks.length; j++)
{
byte[] data = blocks[ j ].getData();
for (int k = 0; k < _blocks_per_big_block; k++)
{
sdbs.add(new SmallDocumentBlock(bigBlockSize, data, k));
}
}
return sdbs;
}
public static DataInputBlock getDataInputBlock(SmallDocumentBlock[] blocks, int offset) {
int firstBlockIndex = offset >> BLOCK_SHIFT;
int firstBlockOffset= offset & BLOCK_MASK;
return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
}
/**
* Calculate the storage size of a set of SmallDocumentBlocks
*
* @param size number of SmallDocumentBlocks
*
* @return total size
*/
public static int calcSize(int size)
{
return size * _block_size;
}
protected int getSmallBlocksPerBigBlock()
{
return _blocks_per_big_block;
}
private static SmallDocumentBlock makeEmptySmallDocumentBlock(POIFSBigBlockSize bigBlockSize)
{
SmallDocumentBlock block = new SmallDocumentBlock(bigBlockSize);
Arrays.fill(block._data, _default_fill);
return block;
}
private static int convertToBlockCount(int size)
{
return (size + _block_size - 1) / _block_size;
}
/**
* Write the storage to an OutputStream
*
* @param stream the OutputStream to which the stored data should
* be written
*
* @exception IOException on problems writing to the specified
* stream
*/
public void writeBlocks(OutputStream stream)
throws IOException
{
stream.write(_data);
}
/**
* Get the data from the block
*
* @return the block's data as a byte array
*
* @exception IOException if there is no data
*/
public byte [] getData() {
return _data;
}
public POIFSBigBlockSize getBigBlockSize() {
return _bigBlockSize;
}
}

View File

@ -0,0 +1,22 @@
/* ====================================================================
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.
==================================================================== */
/**
* storage package contains low level binary structures for POIFS's implementation of the OLE 2
* Compound Document Format.
*/
package org.apache.poi.poifs.storage;

View File

@ -21,10 +21,6 @@ import java.io.FilterOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
/**
*
* @author Josh Micich
*/
public final class LittleEndianOutputStream extends FilterOutputStream implements LittleEndianOutput { public final class LittleEndianOutputStream extends FilterOutputStream implements LittleEndianOutput {
public LittleEndianOutputStream(OutputStream out) { public LittleEndianOutputStream(OutputStream out) {
super(out); super(out);
@ -49,7 +45,7 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
int b3 = (v >>> 24) & 0xFF; int b3 = (v >>> 24) & 0xFF;
int b2 = (v >>> 16) & 0xFF; int b2 = (v >>> 16) & 0xFF;
int b1 = (v >>> 8) & 0xFF; int b1 = (v >>> 8) & 0xFF;
int b0 = (v/* >>> 0*/) & 0xFF; int b0 = (v) & 0xFF;
try { try {
out.write(b0); out.write(b0);
out.write(b1); out.write(b1);
@ -69,7 +65,7 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
@Override @Override
public void writeShort(int v) { public void writeShort(int v) {
int b1 = (v >>> 8) & 0xFF; int b1 = (v >>> 8) & 0xFF;
int b0 = (v/* >>> 0*/) & 0xFF; int b0 = (v) & 0xFF;
try { try {
out.write(b0); out.write(b0);
out.write(b1); out.write(b1);
@ -95,4 +91,37 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
/**
* Put unsigned int into output stream
*
* @param value
* the int (32-bit) value
*/
public void writeUInt( long value ) {
try {
out.write( (byte) ( ( value ) & 0xFF ) );
out.write( (byte) ( ( value >>> 8 ) & 0xFF ) );
out.write( (byte) ( ( value >>> 16 ) & 0xFF ) );
out.write( (byte) ( ( value >>> 24 ) & 0xFF ) );
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Put unsigned short into output stream
*
* @param value
* the unsigned short (16-bit) value
*/
public void putUShort( int value ) {
try {
out.write( (byte) ( ( value ) & 0xFF ) );
out.write( (byte) ( ( value >>> 8 ) & 0xFF ) );
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} }

View File

@ -48,7 +48,6 @@ import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.NotOLE2FileException; import org.apache.poi.poifs.filesystem.NotOLE2FileException;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException; import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.sl.extractor.SlideShowExtractor; import org.apache.poi.sl.extractor.SlideShowExtractor;
@ -79,12 +78,15 @@ import org.apache.xmlbeans.XmlException;
* off switching to <a href="http://tika.apache.org">Apache Tika</a> instead!</p> * off switching to <a href="http://tika.apache.org">Apache Tika</a> instead!</p>
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public class ExtractorFactory { public final class ExtractorFactory {
private static final POILogger logger = POILogFactory.getLogger(ExtractorFactory.class); private static final POILogger logger = POILogFactory.getLogger(ExtractorFactory.class);
public static final String CORE_DOCUMENT_REL = PackageRelationshipTypes.CORE_DOCUMENT; public static final String CORE_DOCUMENT_REL = PackageRelationshipTypes.CORE_DOCUMENT;
protected static final String VISIO_DOCUMENT_REL = PackageRelationshipTypes.VISIO_CORE_DOCUMENT; private static final String VISIO_DOCUMENT_REL = PackageRelationshipTypes.VISIO_CORE_DOCUMENT;
protected static final String STRICT_DOCUMENT_REL = PackageRelationshipTypes.STRICT_CORE_DOCUMENT; private static final String STRICT_DOCUMENT_REL = PackageRelationshipTypes.STRICT_CORE_DOCUMENT;
private ExtractorFactory() {
}
/** /**
* Should this thread prefer event based over usermodel based extractors? * Should this thread prefer event based over usermodel based extractors?
@ -128,6 +130,7 @@ public class ExtractorFactory {
return OLE2ExtractorFactory.getPreferEventExtractor(); return OLE2ExtractorFactory.getPreferEventExtractor();
} }
@SuppressWarnings("unchecked")
public static <T extends POITextExtractor> T createExtractor(File f) throws IOException, OpenXML4JException, XmlException { public static <T extends POITextExtractor> T createExtractor(File f) throws IOException, OpenXML4JException, XmlException {
NPOIFSFileSystem fs = null; NPOIFSFileSystem fs = null;
try { try {
@ -230,13 +233,13 @@ public class ExtractorFactory {
// Is it XSLF? // Is it XSLF?
for (XSLFRelation rel : XSLFPowerPointExtractor.SUPPORTED_TYPES) { for (XSLFRelation rel : XSLFPowerPointExtractor.SUPPORTED_TYPES) {
if ( rel.getContentType().equals( contentType ) ) { if ( rel.getContentType().equals( contentType ) ) {
return new SlideShowExtractor(new XMLSlideShow(pkg)); return new SlideShowExtractor<>(new XMLSlideShow(pkg));
} }
} }
// special handling for SlideShow-Theme-files, // special handling for SlideShow-Theme-files,
if (XSLFRelation.THEME_MANAGER.getContentType().equals(contentType)) { if (XSLFRelation.THEME_MANAGER.getContentType().equals(contentType)) {
return new SlideShowExtractor(new XMLSlideShow(pkg)); return new SlideShowExtractor<>(new XMLSlideShow(pkg));
} }
// How about xlsb? // How about xlsb?
@ -262,10 +265,8 @@ public class ExtractorFactory {
public static <T extends POITextExtractor> T createExtractor(NPOIFSFileSystem fs) throws IOException, OpenXML4JException, XmlException { public static <T extends POITextExtractor> T createExtractor(NPOIFSFileSystem fs) throws IOException, OpenXML4JException, XmlException {
return createExtractor(fs.getRoot()); return createExtractor(fs.getRoot());
} }
public static <T extends POITextExtractor> T createExtractor(OPOIFSFileSystem fs) throws IOException, OpenXML4JException, XmlException {
return createExtractor(fs.getRoot());
}
@SuppressWarnings("unchecked")
public static <T extends POITextExtractor> T createExtractor(DirectoryNode poifsDir) throws IOException, OpenXML4JException, XmlException public static <T extends POITextExtractor> T createExtractor(DirectoryNode poifsDir) throws IOException, OpenXML4JException, XmlException
{ {
// First, check for OOXML // First, check for OOXML
@ -374,7 +375,7 @@ public class ExtractorFactory {
throw new IOException(e.getMessage(), e); throw new IOException(e.getMessage(), e);
} }
} }
return textExtractors.toArray(new POITextExtractor[textExtractors.size()]); return textExtractors.toArray(new POITextExtractor[0]);
} }
/** /**

View File

@ -30,10 +30,9 @@ import java.io.IOException;
import java.util.Locale; import java.util.Locale;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.UnsupportedFileFormatException;
import org.apache.poi.extractor.POIOLE2TextExtractor; import org.apache.poi.extractor.POIOLE2TextExtractor;
import org.apache.poi.extractor.POITextExtractor; import org.apache.poi.extractor.POITextExtractor;
import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.UnsupportedFileFormatException;
import org.apache.poi.hdgf.extractor.VisioTextExtractor; import org.apache.poi.hdgf.extractor.VisioTextExtractor;
import org.apache.poi.hpbf.extractor.PublisherTextExtractor; import org.apache.poi.hpbf.extractor.PublisherTextExtractor;
import org.apache.poi.hsmf.extractor.OutlookTextExtactor; import org.apache.poi.hsmf.extractor.OutlookTextExtactor;
@ -44,14 +43,12 @@ import org.apache.poi.hssf.extractor.ExcelExtractor;
import org.apache.poi.hwpf.extractor.Word6Extractor; import org.apache.poi.hwpf.extractor.Word6Extractor;
import org.apache.poi.hwpf.extractor.WordExtractor; import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ooxml.extractor.ExtractorFactory; import org.apache.poi.ooxml.extractor.ExtractorFactory;
import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.sl.extractor.SlideShowExtractor; import org.apache.poi.sl.extractor.SlideShowExtractor;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.xdgf.extractor.XDGFVisioExtractor; import org.apache.poi.xdgf.extractor.XDGFVisioExtractor;
import org.apache.poi.xssf.extractor.XSSFBEventBasedExcelExtractor; import org.apache.poi.xssf.extractor.XSSFBEventBasedExcelExtractor;
import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor; import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
@ -65,11 +62,10 @@ import org.junit.Test;
*/ */
public class TestExtractorFactory { public class TestExtractorFactory {
private static final POILogger LOG = POILogFactory.getLogger(TestExtractorFactory.class);
private static final POIDataSamples ssTests = POIDataSamples.getSpreadSheetInstance(); private static final POIDataSamples ssTests = POIDataSamples.getSpreadSheetInstance();
private static final File xls = getFileAndCheck(ssTests, "SampleSS.xls"); private static final File xls = getFileAndCheck(ssTests, "SampleSS.xls");
private static final File xlsx = getFileAndCheck(ssTests, "SampleSS.xlsx"); private static final File xlsx = getFileAndCheck(ssTests, "SampleSS.xlsx");
@SuppressWarnings("unused")
private static final File xlsxStrict = getFileAndCheck(ssTests, "SampleSS.strict.xlsx"); private static final File xlsxStrict = getFileAndCheck(ssTests, "SampleSS.strict.xlsx");
private static final File xltx = getFileAndCheck(ssTests, "test.xltx"); private static final File xltx = getFileAndCheck(ssTests, "test.xltx");
private static final File xlsEmb = getFileAndCheck(ssTests, "excel_with_embeded.xls"); private static final File xlsEmb = getFileAndCheck(ssTests, "excel_with_embeded.xls");
@ -150,17 +146,19 @@ public class TestExtractorFactory {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testFileInvalid() throws Exception { public void testFileInvalid() throws Exception {
// Text // Text
try (POITextExtractor te = ExtractorFactory.createExtractor(txt)) {} try (POITextExtractor ignored = ExtractorFactory.createExtractor(txt)) {
fail("extracting from invalid package");
}
} }
@Test @Test
public void testInputStream() throws Exception { public void testInputStream() throws Exception {
testStream((f) -> ExtractorFactory.createExtractor(f), true); testStream(ExtractorFactory::createExtractor, true);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testInputStreamInvalid() throws Exception { public void testInputStreamInvalid() throws Exception {
testInvalid((f) -> ExtractorFactory.createExtractor(f)); testInvalid(ExtractorFactory::createExtractor);
} }
@Test @Test
@ -173,17 +171,6 @@ public class TestExtractorFactory {
testInvalid((f) -> ExtractorFactory.createExtractor(new POIFSFileSystem(f))); testInvalid((f) -> ExtractorFactory.createExtractor(new POIFSFileSystem(f)));
} }
@Test
public void testOPOIFS() throws Exception {
testStream((f) -> ExtractorFactory.createExtractor(new OPOIFSFileSystem(f)), false);
}
@Test(expected = IOException.class)
public void testOPOIFSInvalid() throws Exception {
testInvalid((f) -> ExtractorFactory.createExtractor(new OPOIFSFileSystem(f)));
}
private void testStream(final FunctionEx<FileInputStream, POITextExtractor> poifsIS, final boolean loadOOXML) private void testStream(final FunctionEx<FileInputStream, POITextExtractor> poifsIS, final boolean loadOOXML)
throws IOException, OpenXML4JException, XmlException { throws IOException, OpenXML4JException, XmlException {
for (int i = 0; i < TEST_SET.length; i += 4) { for (int i = 0; i < TEST_SET.length; i += 4) {
@ -213,7 +200,8 @@ public class TestExtractorFactory {
private void testInvalid(FunctionEx<FileInputStream, POITextExtractor> poifs) throws IOException, OpenXML4JException, XmlException { private void testInvalid(FunctionEx<FileInputStream, POITextExtractor> poifs) throws IOException, OpenXML4JException, XmlException {
// Text // Text
try (FileInputStream fis = new FileInputStream(txt); try (FileInputStream fis = new FileInputStream(txt);
POITextExtractor te = poifs.apply(fis)) { POITextExtractor ignored = poifs.apply(fis)) {
fail("extracting from invalid package");
} }
} }
@ -237,7 +225,9 @@ public class TestExtractorFactory {
public void testPackageInvalid() throws Exception { public void testPackageInvalid() throws Exception {
// Text // Text
try (final OPCPackage pkg = OPCPackage.open(txt, PackageAccess.READ); try (final OPCPackage pkg = OPCPackage.open(txt, PackageAccess.READ);
final POITextExtractor te = ExtractorFactory.createExtractor(pkg)) {} final POITextExtractor ignored = ExtractorFactory.createExtractor(pkg)) {
fail("extracting from invalid package");
}
} }
@Test @Test
@ -452,7 +442,7 @@ public class TestExtractorFactory {
}; };
@Test @Test
public void testFileLeak() throws Exception { public void testFileLeak() {
// run a number of files that might fail in order to catch // run a number of files that might fail in order to catch
// leaked file resources when using file-leak-detector while // leaked file resources when using file-leak-detector while
// running the test // running the test

View File

@ -27,7 +27,6 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
@ -35,12 +34,10 @@ import java.util.List;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.usermodel.HSLFObjectShape; import org.apache.poi.hslf.usermodel.HSLFObjectShape;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.sl.extractor.SlideShowExtractor; import org.apache.poi.sl.extractor.SlideShowExtractor;
import org.apache.poi.sl.usermodel.ObjectShape; import org.apache.poi.sl.usermodel.ObjectShape;
@ -68,18 +65,7 @@ public final class TestExtractor {
*/ */
private static POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); private static POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
// @Before @SuppressWarnings("unchecked")
// public void setUp() throws Exception {
// ppe = new PowerPointExtractor(slTests.getFile("basic_test_ppt_file.ppt").getCanonicalPath());
// ppe2 = new PowerPointExtractor(slTests.getFile("with_textbox.ppt").getCanonicalPath());
// }
// @After
// public void closeResources() throws Exception {
// ppe2.close();
// ppe.close();
// }
private SlideShowExtractor<?,?> openExtractor(String fileName) throws IOException { private SlideShowExtractor<?,?> openExtractor(String fileName) throws IOException {
try (InputStream is = slTests.openResourceAsStream(fileName)) { try (InputStream is = slTests.openResourceAsStream(fileName)) {
return new SlideShowExtractor(SlideShowFactory.create(is)); return new SlideShowExtractor(SlideShowFactory.create(is));
@ -151,8 +137,6 @@ public final class TestExtractor {
/** /**
* Test that when presented with a PPT file missing the odd * Test that when presented with a PPT file missing the odd
* core record, we can still get the rest of the text out * core record, we can still get the rest of the text out
*
* @throws Exception
*/ */
@Test @Test
public void testMissingCoreRecords() throws IOException { public void testMissingCoreRecords() throws IOException {
@ -191,7 +175,7 @@ public final class TestExtractor {
assertTrue(dir.hasEntry(HSLFSlideShow.POWERPOINT_DOCUMENT)); assertTrue(dir.hasEntry(HSLFSlideShow.POWERPOINT_DOCUMENT));
try (final SlideShow<?,?> ppt = SlideShowFactory.create(dir); try (final SlideShow<?,?> ppt = SlideShowFactory.create(dir);
final SlideShowExtractor<?,?> ppe = new SlideShowExtractor(ppt)) { final SlideShowExtractor<?,?> ppe = new SlideShowExtractor<>(ppt)) {
assertEquals(TEST_SET[i+1], ppe.getText()); assertEquals(TEST_SET[i+1], ppe.getText());
} }
} }
@ -297,7 +281,7 @@ public final class TestExtractor {
} }
private void testHeaderFooterInner(final HSLFSlideShow ppt) throws IOException { private void testHeaderFooterInner(final HSLFSlideShow ppt) throws IOException {
try (final SlideShowExtractor<?,?> ppe = new SlideShowExtractor(ppt)) { try (final SlideShowExtractor<?,?> ppe = new SlideShowExtractor<>(ppt)) {
String text = ppe.getText(); String text = ppe.getText();
assertFalse("Header shouldn't be there by default\n" + text, text.contains("testdoc")); assertFalse("Header shouldn't be there by default\n" + text, text.contains("testdoc"));
assertFalse("Header shouldn't be there by default\n" + text, text.contains("test phrase")); assertFalse("Header shouldn't be there by default\n" + text, text.contains("test phrase"));
@ -399,19 +383,11 @@ public final class TestExtractor {
public void testDifferentPOIFS() throws IOException { public void testDifferentPOIFS() throws IOException {
// Open the two filesystems // Open the two filesystems
File pptFile = slTests.getFile("basic_test_ppt_file.ppt"); File pptFile = slTests.getFile("basic_test_ppt_file.ppt");
try (final InputStream is1 = new FileInputStream(pptFile); try (final NPOIFSFileSystem npoifs = new NPOIFSFileSystem(pptFile, true)) {
final NPOIFSFileSystem npoifs = new NPOIFSFileSystem(pptFile)) {
final OPOIFSFileSystem opoifs = new OPOIFSFileSystem(is1);
DirectoryNode[] files = {opoifs.getRoot(), npoifs.getRoot()};
// Open directly // Open directly
for (DirectoryNode dir : files) { try (SlideShow<?,?> ppt = SlideShowFactory.create(npoifs.getRoot());
try (SlideShow<?,?> ppt = SlideShowFactory.create(dir); SlideShowExtractor<?,?> extractor = new SlideShowExtractor<>(ppt)) {
SlideShowExtractor<?,?> extractor = new SlideShowExtractor(ppt)) { assertEquals(expectText, extractor.getText());
assertEquals(expectText, extractor.getText());
}
} }
} }
} }

View File

@ -24,7 +24,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -36,7 +35,6 @@ import org.apache.poi.hwpf.OldWordFileFormatException;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
import org.junit.Test; import org.junit.Test;
@ -48,7 +46,7 @@ public final class TestWordExtractor {
private static POIDataSamples docTests = POIDataSamples.getDocumentInstance(); private static POIDataSamples docTests = POIDataSamples.getDocumentInstance();
public static void assertEqualsTrim( String expected, String actual ) private static void assertEqualsTrim( String expected, String actual )
{ {
String newExpected = expected.replaceAll( "\r\n", "\n" ) String newExpected = expected.replaceAll( "\r\n", "\n" )
.replaceAll( "\r", "\n" ).trim(); .replaceAll( "\r", "\n" ).trim();
@ -188,7 +186,8 @@ public final class TestWordExtractor {
HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("ThreeColHeadFoot.doc"); HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("ThreeColHeadFoot.doc");
WordExtractor extractor1 = new WordExtractor(doc1); WordExtractor extractor1 = new WordExtractor(doc1);
assertEquals("First header column!\tMid header Right header!\n", extractor1.getHeaderText()); //noinspection deprecation
assertEquals("First header column!\tMid header Right header!\n", extractor1.getHeaderText());
assertContains(extractor1.getText(), "First header column!"); assertContains(extractor1.getText(), "First header column!");
extractor1.close(); extractor1.close();
doc1.close(); doc1.close();
@ -197,7 +196,8 @@ public final class TestWordExtractor {
HWPFDocument doc2 = HWPFTestDataSamples.openSampleFile("HeaderFooterUnicode.doc"); HWPFDocument doc2 = HWPFTestDataSamples.openSampleFile("HeaderFooterUnicode.doc");
WordExtractor extractor2 = new WordExtractor(doc2); WordExtractor extractor2 = new WordExtractor(doc2);
assertEquals("This is a simple header, with a \u20ac euro symbol in it.\n\n", extractor2.getHeaderText()); //noinspection deprecation
assertEquals("This is a simple header, with a \u20ac euro symbol in it.\n\n", extractor2.getHeaderText());
assertContains(extractor2.getText(), "This is a simple header"); assertContains(extractor2.getText(), "This is a simple header");
extractor2.close(); extractor2.close();
doc2.close(); doc2.close();
@ -209,7 +209,8 @@ public final class TestWordExtractor {
HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("ThreeColHeadFoot.doc"); HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("ThreeColHeadFoot.doc");
WordExtractor extractor1 = new WordExtractor(doc1); WordExtractor extractor1 = new WordExtractor(doc1);
assertEquals("Footer Left\tFooter Middle Footer Right\n", extractor1.getFooterText()); //noinspection deprecation
assertEquals("Footer Left\tFooter Middle Footer Right\n", extractor1.getFooterText());
assertContains(extractor1.getText(), "Footer Left"); assertContains(extractor1.getText(), "Footer Left");
extractor1.close(); extractor1.close();
doc1.close(); doc1.close();
@ -218,7 +219,8 @@ public final class TestWordExtractor {
HWPFDocument doc2 = HWPFTestDataSamples.openSampleFile("HeaderFooterUnicode.doc"); HWPFDocument doc2 = HWPFTestDataSamples.openSampleFile("HeaderFooterUnicode.doc");
WordExtractor extractor2 = new WordExtractor(doc2); WordExtractor extractor2 = new WordExtractor(doc2);
assertEquals("The footer, with Moli\u00e8re, has Unicode in it.\n", extractor2.getFooterText()); //noinspection deprecation
assertEquals("The footer, with Moli\u00e8re, has Unicode in it.\n", extractor2.getFooterText());
assertContains(extractor2.getText(), "The footer, with"); assertContains(extractor2.getText(), "The footer, with");
extractor2.close(); extractor2.close();
doc2.close(); doc2.close();
@ -279,6 +281,7 @@ public final class TestWordExtractor {
assertContains(text, "Paragraph 3. Has some RED text and some BLUE BOLD text in it"); assertContains(text, "Paragraph 3. Has some RED text and some BLUE BOLD text in it");
assertContains(text, "Last (4th) paragraph"); assertContains(text, "Last (4th) paragraph");
@SuppressWarnings("deprecation")
String[] tp = w6e.getParagraphText(); String[] tp = w6e.getParagraphText();
assertEquals(7, tp.length); assertEquals(7, tp.length);
assertEquals("The quick brown fox jumps over the lazy dog\r\n", tp[0]); assertEquals("The quick brown fox jumps over the lazy dog\r\n", tp[0]);
@ -299,17 +302,17 @@ public final class TestWordExtractor {
@Test @Test
public void testWord6() throws Exception { public void testWord6() throws Exception {
InputStream is = docTests.openResourceAsStream("Word6.doc"); try (InputStream is = docTests.openResourceAsStream("Word6.doc");
Word6Extractor w6e = new Word6Extractor(is); Word6Extractor w6e = new Word6Extractor(is)) {
is.close(); String text = w6e.getText();
String text = w6e.getText();
assertContains(text, "The quick brown fox jumps over the lazy dog");
assertContains(text, "The quick brown fox jumps over the lazy dog");
@SuppressWarnings("deprecation")
String[] tp = w6e.getParagraphText(); String[] tp = w6e.getParagraphText();
assertEquals(1, tp.length); assertEquals(1, tp.length);
assertEquals("The quick brown fox jumps over the lazy dog\r\n", tp[0]); assertEquals("The quick brown fox jumps over the lazy dog\r\n", tp[0]);
w6e.close(); }
} }
@Test @Test
@ -341,30 +344,23 @@ public final class TestWordExtractor {
public void testDifferentPOIFS() throws Exception { public void testDifferentPOIFS() throws Exception {
// Open the two filesystems // Open the two filesystems
File file = docTests.getFile("test2.doc"); File file = docTests.getFile("test2.doc");
InputStream is = new FileInputStream(file); try (NPOIFSFileSystem npoifs = new NPOIFSFileSystem(file, true)) {
OPOIFSFileSystem opoifs = new OPOIFSFileSystem(is);
is.close(); DirectoryNode dir = npoifs.getRoot();
NPOIFSFileSystem npoifs = new NPOIFSFileSystem(file);
// Open directly
DirectoryNode[] files = { opoifs.getRoot(), npoifs.getRoot() }; @SuppressWarnings("resource")
WordExtractor extractor1 = new WordExtractor(dir);
// Open directly assertEqualsTrim(p_text1_block, extractor1.getText());
for(DirectoryNode dir : files) { // extractor.close();
@SuppressWarnings("resource")
WordExtractor extractor = new WordExtractor(dir); // Open via a HWPFDocument
assertEqualsTrim(p_text1_block, extractor.getText()); try (HWPFDocument doc = new HWPFDocument(dir);
// extractor.close(); WordExtractor extractor2 = new WordExtractor(doc)) {
} assertEqualsTrim(p_text1_block, extractor2.getText());
}
// Open via a HWPFDocument
for(DirectoryNode dir : files) {
HWPFDocument doc = new HWPFDocument(dir);
WordExtractor extractor = new WordExtractor(doc);
assertEqualsTrim(p_text1_block, extractor.getText());
extractor.close();
} }
npoifs.close();
} }
/** /**
@ -381,11 +377,8 @@ public final class TestWordExtractor {
for (Entry entry : fs.getRoot()) { for (Entry entry : fs.getRoot()) {
if ("WordDocument".equals(entry.getName())) { if ("WordDocument".equals(entry.getName())) {
WordExtractor ex = new WordExtractor(fs); try (WordExtractor ex = new WordExtractor(fs)) {
try {
text = ex.getText(); text = ex.getText();
} finally {
ex.close();
} }
} }
} }
@ -396,35 +389,22 @@ public final class TestWordExtractor {
@Test @Test
public void testExtractorFromWord6Extractor() throws Exception { public void testExtractorFromWord6Extractor() throws Exception {
InputStream is = POIDataSamples.getHPSFInstance().openResourceAsStream("TestMickey.doc"); try (InputStream is = POIDataSamples.getHPSFInstance().openResourceAsStream("TestMickey.doc");
POIFSFileSystem fs = new POIFSFileSystem(is); POIFSFileSystem fs = new POIFSFileSystem(is);
is.close(); Word6Extractor wExt = new Word6Extractor(fs);
Word6Extractor wExt = new Word6Extractor(fs); POITextExtractor ext = wExt.getMetadataTextExtractor()) {
try { // Now overall
POITextExtractor ext = wExt.getMetadataTextExtractor(); String text = ext.getText();
try { assertContains(text, "TEMPLATE = Normal");
// Now overall assertContains(text, "SUBJECT = sample subject");
String text = ext.getText(); assertContains(text, "MANAGER = sample manager");
assertContains(text, "TEMPLATE = Normal"); assertContains(text, "COMPANY = sample company");
assertContains(text, "SUBJECT = sample subject");
assertContains(text, "MANAGER = sample manager");
assertContains(text, "COMPANY = sample company");
} finally {
ext.close();
}
} finally {
wExt.close();
fs.close();
} }
} }
private WordExtractor openExtractor(String fileName) throws IOException { private WordExtractor openExtractor(String fileName) throws IOException {
InputStream is = docTests.openResourceAsStream(fileName); try (InputStream is = docTests.openResourceAsStream(fileName)) {
try {
return new WordExtractor(is); return new WordExtractor(is);
} finally {
is.close();
} }
} }
} }

View File

@ -32,7 +32,6 @@ import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.HWPFTestCase; import org.apache.poi.hwpf.HWPFTestCase;
import org.apache.poi.hwpf.HWPFTestDataSamples; import org.apache.poi.hwpf.HWPFTestDataSamples;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;
@ -99,16 +98,9 @@ public final class TestHWPFWrite extends HWPFTestCase {
public void testInPlaceWrite() throws Exception { public void testInPlaceWrite() throws Exception {
// Setup as a copy of a known-good file // Setup as a copy of a known-good file
final File file = TempFile.createTempFile("TestDocument", ".doc"); final File file = TempFile.createTempFile("TestDocument", ".doc");
InputStream inputStream = SAMPLES.openResourceAsStream("SampleDoc.doc"); try (InputStream inputStream = SAMPLES.openResourceAsStream("SampleDoc.doc");
try { FileOutputStream outputStream = new FileOutputStream(file)) {
FileOutputStream outputStream = new FileOutputStream(file); IOUtils.copy(inputStream, outputStream);
try {
IOUtils.copy(inputStream, outputStream);
} finally {
outputStream.close();
}
} finally {
inputStream.close();
} }
// Open from the temp file in read-write mode // Open from the temp file in read-write mode
@ -136,28 +128,13 @@ public final class TestHWPFWrite extends HWPFTestCase {
@Test(expected=IllegalStateException.class) @Test(expected=IllegalStateException.class)
public void testInvalidInPlaceWriteInputStream() throws IOException { public void testInvalidInPlaceWriteInputStream() throws IOException {
// Can't work for InputStream opened files // Can't work for InputStream opened files
InputStream is = SAMPLES.openResourceAsStream("SampleDoc.doc");
HWPFDocument doc = new HWPFDocument(is); try (InputStream is = SAMPLES.openResourceAsStream("SampleDoc.doc");
is.close(); HWPFDocument doc = new HWPFDocument(is)) {
try {
doc.write(); doc.write();
} finally {
doc.close();
} }
} }
@Test(expected=IllegalStateException.class)
public void testInvalidInPlaceWriteOPOIFS() throws Exception {
// Can't work for OPOIFS
OPOIFSFileSystem ofs = new OPOIFSFileSystem(SAMPLES.openResourceAsStream("SampleDoc.doc"));
HWPFDocument doc = new HWPFDocument(ofs.getRoot());
try {
doc.write();
} finally {
doc.close();
}
}
@Test(expected=IllegalStateException.class) @Test(expected=IllegalStateException.class)
public void testInvalidInPlaceWriteNPOIFS() throws Exception { public void testInvalidInPlaceWriteNPOIFS() throws Exception {
// Can't work for Read-Only files // Can't work for Read-Only files

View File

@ -31,7 +31,7 @@ import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -78,7 +78,7 @@ public final class TestPOIDocumentMain {
assertNotNull(doc2.getSummaryInformation()); assertNotNull(doc2.getSummaryInformation());
assertEquals("Avik Sengupta", doc2.getSummaryInformation().getAuthor()); assertEquals("Avik Sengupta", doc2.getSummaryInformation().getAuthor());
assertEquals(null, doc2.getSummaryInformation().getKeywords()); assertNull(doc2.getSummaryInformation().getKeywords());
assertEquals(0, doc2.getDocumentSummaryInformation().getByteCount()); assertEquals(0, doc2.getDocumentSummaryInformation().getByteCount());
} }
@ -110,7 +110,7 @@ public final class TestPOIDocumentMain {
// Create a new version // Create a new version
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
OPOIFSFileSystem inFS = new OPOIFSFileSystem(bais); POIFSFileSystem inFS = new POIFSFileSystem(bais);
// Check they're still there // Check they're still there
POIDocument doc3 = new HPSFPropertiesOnlyDocument(inFS); POIDocument doc3 = new HPSFPropertiesOnlyDocument(inFS);

View File

@ -21,6 +21,7 @@ import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -28,7 +29,6 @@ import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -51,7 +51,6 @@ import org.apache.poi.hpsf.NoPropertySetStreamException;
import org.apache.poi.hpsf.Property; import org.apache.poi.hpsf.Property;
import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.PropertySetFactory;
import org.apache.poi.hpsf.ReadingNotSupportedException;
import org.apache.poi.hpsf.Section; import org.apache.poi.hpsf.Section;
import org.apache.poi.hpsf.SummaryInformation; import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.hpsf.UnsupportedVariantTypeException; import org.apache.poi.hpsf.UnsupportedVariantTypeException;
@ -94,8 +93,6 @@ public class TestWrite {
"LANG environment variable to a proper value, e.g. " + "LANG environment variable to a proper value, e.g. " +
"\"de_DE\"."; "\"de_DE\".";
POIFile[] poiFiles;
@BeforeClass @BeforeClass
public static void setUp() { public static void setUp() {
VariantSupport.setLogUnsupportedTypes(false); VariantSupport.setLogUnsupportedTypes(false);
@ -113,24 +110,20 @@ public class TestWrite {
/* Create a mutable property set with a section that does not have the /* Create a mutable property set with a section that does not have the
* formatID set: */ * formatID set: */
final OutputStream out = new FileOutputStream(filename);
final POIFSFileSystem poiFs = new POIFSFileSystem();
final PropertySet ps = new PropertySet(); final PropertySet ps = new PropertySet();
ps.clearSections(); ps.clearSections();
ps.addSection(new Section()); ps.addSection(new Section());
/* Write it to a POIFS and the latter to disk: */ /* Write it to a POIFS and the latter to disk: */
try { try (OutputStream out = new FileOutputStream(filename);
POIFSFileSystem poiFs = new POIFSFileSystem()) {
final ByteArrayOutputStream psStream = new ByteArrayOutputStream(); final ByteArrayOutputStream psStream = new ByteArrayOutputStream();
ps.write(psStream); ps.write(psStream);
psStream.close(); psStream.close();
final byte[] streamData = psStream.toByteArray(); final byte[] streamData = psStream.toByteArray();
poiFs.createDocument(new ByteArrayInputStream(streamData), poiFs.createDocument(new ByteArrayInputStream(streamData),
SummaryInformation.DEFAULT_STREAM_NAME); SummaryInformation.DEFAULT_STREAM_NAME);
poiFs.writeFilesystem(out); poiFs.writeFilesystem(out);
} finally {
poiFs.close();
out.close();
} }
} }
@ -170,12 +163,7 @@ public class TestWrite {
final POIFSReader r = new POIFSReader(); final POIFSReader r = new POIFSReader();
r.registerListener(new MyPOIFSReaderListener(), r.registerListener(new MyPOIFSReaderListener(),
SummaryInformation.DEFAULT_STREAM_NAME); SummaryInformation.DEFAULT_STREAM_NAME);
FileInputStream stream = new FileInputStream(filename); r.read(filename);
try {
r.read(stream);
} finally {
stream.close();
}
} }
@ -221,24 +209,16 @@ public class TestWrite {
/* Read the POIFS: */ /* Read the POIFS: */
final PropertySet[] psa = new PropertySet[1]; final PropertySet[] psa = new PropertySet[1];
final POIFSReader r = new POIFSReader(); final POIFSReader r = new POIFSReader();
r.registerListener(new POIFSReaderListener() { final POIFSReaderListener listener = event -> {
@Override try {
public void processPOIFSReaderEvent(final POIFSReaderEvent event) { psa[0] = PropertySetFactory.create(event.getStream());
try { } catch (Exception ex) {
psa[0] = PropertySetFactory.create(event.getStream()); fail(ex.getMessage());
} catch (Exception ex) { }
fail(ex.getMessage()); };
} r.registerListener(listener, SummaryInformation.DEFAULT_STREAM_NAME);
}},
SummaryInformation.DEFAULT_STREAM_NAME r.read(filename);
);
InputStream stream = new FileInputStream(filename);
try {
r.read(stream);
} finally {
stream.close();
}
assertNotNull(psa[0]); assertNotNull(psa[0]);
assertTrue(psa[0].isSummaryInformation()); assertTrue(psa[0].isSummaryInformation());
@ -295,23 +275,17 @@ public class TestWrite {
/* Read the POIFS: */ /* Read the POIFS: */
final PropertySet[] psa = new PropertySet[1]; final PropertySet[] psa = new PropertySet[1];
final POIFSReader r = new POIFSReader(); final POIFSReader r = new POIFSReader();
r.registerListener(new POIFSReaderListener() { final POIFSReaderListener listener = (event) -> {
@Override try {
public void processPOIFSReaderEvent(final POIFSReaderEvent event) { psa[0] = PropertySetFactory.create(event.getStream());
try { } catch (Exception ex) {
psa[0] = PropertySetFactory.create(event.getStream()); fail(ex.getMessage());
} catch (Exception ex) { }
throw new RuntimeException(ex); };
}
} r.registerListener(listener,STREAM_NAME);
}, r.read(filename);
STREAM_NAME);
FileInputStream stream = new FileInputStream(filename);
try {
r.read(stream);
} finally {
stream.close();
}
assertNotNull(psa[0]); assertNotNull(psa[0]);
Section s = (psa[0].getSections().get(0)); Section s = (psa[0].getSections().get(0));
assertEquals(s.getFormatID(), formatID); assertEquals(s.getFormatID(), formatID);
@ -338,12 +312,8 @@ public class TestWrite {
/** /**
* <p>Writes and reads back various variant types and checks whether the * Writes and reads back various variant types and checks whether the
* stuff that has been read back equals the stuff that was written.</p> * stuff that has been read back equals the stuff that was written.
* @throws IOException
* @throws UnsupportedEncodingException
* @throws UnsupportedVariantTypeException
* @throws ReadingNotSupportedException
*/ */
@Test @Test
public void variantTypes() throws Exception { public void variantTypes() throws Exception {
@ -379,9 +349,8 @@ public class TestWrite {
* was written. * was written.
*/ */
@Test @Test
public void codepages() throws ReadingNotSupportedException, UnsupportedVariantTypeException, IOException public void codepages() throws UnsupportedVariantTypeException, IOException
{ {
Throwable thr = null;
final int[] validCodepages = {CODEPAGE_DEFAULT, CodePageUtil.CP_UTF8, CodePageUtil.CP_UNICODE, CodePageUtil.CP_WINDOWS_1252}; final int[] validCodepages = {CODEPAGE_DEFAULT, CodePageUtil.CP_UTF8, CodePageUtil.CP_UNICODE, CodePageUtil.CP_WINDOWS_1252};
for (final int cp : validCodepages) { for (final int cp : validCodepages) {
if (cp == -1 && !hasProperDefaultCharset()) if (cp == -1 && !hasProperDefaultCharset())
@ -400,9 +369,8 @@ public class TestWrite {
final int[] invalidCodepages = new int[] {0, 1, 2, 4711, 815}; final int[] invalidCodepages = new int[] {0, 1, 2, 4711, 815};
for (int cp : invalidCodepages) { for (int cp : invalidCodepages) {
final long type = (cp == CodePageUtil.CP_UNICODE) ? Variant.VT_LPWSTR : Variant.VT_LPSTR;
try { try {
checkString(type, "\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc\u00df", cp); checkString(Variant.VT_LPSTR, "\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc\u00df", cp);
fail("UnsupportedEncodingException for codepage " + cp + " expected."); fail("UnsupportedEncodingException for codepage " + cp + " expected.");
} catch (UnsupportedEncodingException ex) { } catch (UnsupportedEncodingException ex) {
/* This is the expected behaviour. */ /* This is the expected behaviour. */
@ -441,7 +409,7 @@ public class TestWrite {
} }
private void checkString(final long variantType, final String value, final int codepage) private void checkString(final long variantType, final String value, final int codepage)
throws UnsupportedVariantTypeException, IOException, ReadingNotSupportedException, UnsupportedEncodingException { throws UnsupportedVariantTypeException, IOException {
for (int i=0; i<value.length(); i++) { for (int i=0; i<value.length(); i++) {
check(variantType, value.substring(0, i), codepage); check(variantType, value.substring(0, i), codepage);
} }
@ -457,7 +425,7 @@ public class TestWrite {
* @throws IOException if an I/O exception occurs. * @throws IOException if an I/O exception occurs.
*/ */
private void check(final long variantType, final Object value, final int codepage) private void check(final long variantType, final Object value, final int codepage)
throws UnsupportedVariantTypeException, IOException, ReadingNotSupportedException, UnsupportedEncodingException throws UnsupportedVariantTypeException, IOException
{ {
final ByteArrayOutputStream out = new ByteArrayOutputStream(); final ByteArrayOutputStream out = new ByteArrayOutputStream();
VariantSupport.write(out, variantType, value, codepage); VariantSupport.write(out, variantType, value, codepage);
@ -474,8 +442,6 @@ public class TestWrite {
/** /**
* <p>Tests writing and reading back a proper dictionary.</p> * <p>Tests writing and reading back a proper dictionary.</p>
* @throws IOException
* @throws HPSFException
*/ */
@Test @Test
public void dictionary() throws IOException, HPSFException { public void dictionary() throws IOException, HPSFException {
@ -488,9 +454,9 @@ public class TestWrite {
final PropertySet ps1 = new PropertySet(); final PropertySet ps1 = new PropertySet();
final Section s = ps1.getSections().get(0); final Section s = ps1.getSections().get(0);
final Map<Long,String> m = new HashMap<>(3, 1.0f); final Map<Long,String> m = new HashMap<>(3, 1.0f);
m.put(Long.valueOf(1), "String 1"); m.put(1L, "String 1");
m.put(Long.valueOf(2), "String 2"); m.put(2L, "String 2");
m.put(Long.valueOf(3), "String 3"); m.put(3L, "String 3");
s.setDictionary(m); s.setDictionary(m);
s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]); s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]);
int codepage = CodePageUtil.CP_UNICODE; int codepage = CodePageUtil.CP_UNICODE;
@ -522,12 +488,12 @@ public class TestWrite {
*/ */
@Test @Test
public void inPlaceNPOIFSWrite() throws Exception { public void inPlaceNPOIFSWrite() throws Exception {
NPOIFSFileSystem fs = null; NPOIFSFileSystem fs;
DirectoryEntry root = null; DirectoryEntry root;
DocumentNode sinfDoc = null; DocumentNode sinfDoc;
DocumentNode dinfDoc = null; DocumentNode dinfDoc;
SummaryInformation sinf = null; SummaryInformation sinf;
DocumentSummaryInformation dinf = null; DocumentSummaryInformation dinf;
// We need to work on a File for in-place changes, so create a temp one // We need to work on a File for in-place changes, so create a temp one
final File copy = TempFile.createTempFile("Test-HPSF", "ole2"); final File copy = TempFile.createTempFile("Test-HPSF", "ole2");
@ -567,10 +533,13 @@ public class TestWrite {
assertEquals("\u7b2c1\u7ae0", sinf.getTitle()); assertEquals("\u7b2c1\u7ae0", sinf.getTitle());
assertEquals("", dinf.getCompany()); assertEquals("", dinf.getCompany());
assertEquals(null, dinf.getManager()); assertNull(dinf.getManager());
// Do an in-place replace via an InputStream // Do an in-place replace via an InputStream
assertNotNull(sinfDoc);
assertNotNull(dinfDoc);
new NPOIFSDocument(sinfDoc).replaceContents(sinf.toInputStream()); new NPOIFSDocument(sinfDoc).replaceContents(sinf.toInputStream());
new NPOIFSDocument(dinfDoc).replaceContents(dinf.toInputStream()); new NPOIFSDocument(dinfDoc).replaceContents(dinf.toInputStream());
@ -661,7 +630,7 @@ public class TestWrite {
assertEquals("\u7b2c1\u7ae0", sinf.getTitle()); assertEquals("\u7b2c1\u7ae0", sinf.getTitle());
assertEquals("", dinf.getCompany()); assertEquals("", dinf.getCompany());
assertEquals(null, dinf.getManager()); assertNull(dinf.getManager());
// Now alter a few of them // Now alter a few of them
@ -730,43 +699,37 @@ public class TestWrite {
// Tidy up // Tidy up
fs.close(); fs.close();
//noinspection ResultOfMethodCallIgnored
copy.delete(); copy.delete();
} }
/** /**
* <p>Tests writing and reading back a proper dictionary with an invalid * Tests writing and reading back a proper dictionary with an invalid
* codepage. (HPSF writes Unicode dictionaries only.)</p> * codepage. (HPSF writes Unicode dictionaries only.)
* @throws IOException
* @throws HPSFException
*/ */
@Test(expected=IllegalPropertySetDataException.class) @Test(expected=UnsupportedEncodingException.class)
public void dictionaryWithInvalidCodepage() throws IOException, HPSFException { public void dictionaryWithInvalidCodepage() throws IOException, HPSFException {
final File copy = TempFile.createTempFile("Test-HPSF", "ole2"); final File copy = TempFile.createTempFile("Test-HPSF", "ole2");
copy.deleteOnExit(); copy.deleteOnExit();
/* Write: */ /* Write: */
final OutputStream out = new FileOutputStream(copy);
final POIFSFileSystem poiFs = new POIFSFileSystem();
final PropertySet ps1 = new PropertySet(); final PropertySet ps1 = new PropertySet();
final Section s = ps1.getSections().get(0); final Section s = ps1.getSections().get(0);
final Map<Long,String> m = new HashMap<>(3, 1.0f); final Map<Long,String> m = new HashMap<>(3, 1.0f);
m.put(Long.valueOf(1), "String 1"); m.put(1L, "String 1");
m.put(Long.valueOf(2), "String 2"); m.put(2L, "String 2");
m.put(Long.valueOf(3), "String 3"); m.put(3L, "String 3");
try { try (OutputStream out = new FileOutputStream(copy);
POIFSFileSystem poiFs = new POIFSFileSystem()) {
s.setDictionary(m); s.setDictionary(m);
s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]); s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]);
int codepage = 12345; int codepage = 12345;
s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage);
Integer.valueOf(codepage));
poiFs.createDocument(ps1.toInputStream(), "Test"); poiFs.createDocument(ps1.toInputStream(), "Test");
poiFs.writeFilesystem(out); poiFs.writeFilesystem(out);
} finally {
poiFs.close();
out.close();
} }
} }

View File

@ -18,8 +18,9 @@
package org.apache.poi.hpsf.basic; package org.apache.poi.hpsf.basic;
import static org.junit.Assert.fail;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -28,7 +29,6 @@ import java.util.List;
import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.poifs.eventfilesystem.POIFSReader; import org.apache.poi.poifs.eventfilesystem.POIFSReader;
import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
@ -39,6 +39,9 @@ import org.apache.poi.util.IOUtils;
*/ */
final class Util { final class Util {
private Util() {
}
/** /**
* <p>Reads a set of files from a POI filesystem and returns them * <p>Reads a set of files from a POI filesystem and returns them
* as an array of {@link POIFile} instances. This method loads all * as an array of {@link POIFile} instances. This method loads all
@ -58,24 +61,20 @@ final class Util {
* *
* @exception IOException if an I/O exception occurs * @exception IOException if an I/O exception occurs
*/ */
public static List<POIFile> readPOIFiles(final File poiFs, final String... poiFiles) static List<POIFile> readPOIFiles(final File poiFs, final String... poiFiles) throws IOException {
throws FileNotFoundException, IOException {
final List<POIFile> files = new ArrayList<>(); final List<POIFile> files = new ArrayList<>();
POIFSReader r = new POIFSReader(); POIFSReader r = new POIFSReader();
POIFSReaderListener pfl = new POIFSReaderListener() { POIFSReaderListener pfl = event -> {
@Override try {
public void processPOIFSReaderEvent(final POIFSReaderEvent event) { final POIFile f = new POIFile();
try { f.setName(event.getName());
final POIFile f = new POIFile(); f.setPath(event.getPath());
f.setName(event.getName()); final InputStream in = event.getStream();
f.setPath(event.getPath()); f.setBytes(IOUtils.toByteArray(in));
final InputStream in = event.getStream(); in.close();
f.setBytes(IOUtils.toByteArray(in)); files.add(f);
in.close(); } catch (IOException ex) {
files.add(f); fail(ex.getMessage());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
} }
}; };
if (poiFiles.length == 0) { if (poiFiles.length == 0) {
@ -88,12 +87,8 @@ final class Util {
} }
/* Read the POI filesystem. */ /* Read the POI filesystem. */
FileInputStream stream = new FileInputStream(poiFs); r.read(poiFs);
try {
r.read(stream);
} finally {
stream.close();
}
return files; return files;
} }
@ -110,29 +105,23 @@ final class Util {
* @return The property sets. The elements are ordered in the same way * @return The property sets. The elements are ordered in the same way
* as the files in the POI filesystem. * as the files in the POI filesystem.
* *
* @exception FileNotFoundException if the file containing the POI
* filesystem does not exist
*
* @exception IOException if an I/O exception occurs * @exception IOException if an I/O exception occurs
*/ */
public static List<POIFile> readPropertySets(final File poiFs) throws IOException { static List<POIFile> readPropertySets(final File poiFs) throws IOException {
final List<POIFile> files = new ArrayList<>(7); final List<POIFile> files = new ArrayList<>(7);
final POIFSReader r = new POIFSReader(); final POIFSReader r = new POIFSReader();
POIFSReaderListener pfl = new POIFSReaderListener() { final POIFSReaderListener pfl = event -> {
@Override try {
public void processPOIFSReaderEvent(final POIFSReaderEvent event) { final POIFile f = new POIFile();
try { f.setName(event.getName());
final POIFile f = new POIFile(); f.setPath(event.getPath());
f.setName(event.getName()); final InputStream in = event.getStream();
f.setPath(event.getPath()); if (PropertySet.isPropertySetStream(in)) {
final InputStream in = event.getStream(); f.setBytes(IOUtils.toByteArray(in));
if (PropertySet.isPropertySetStream(in)) { files.add(f);
f.setBytes(IOUtils.toByteArray(in));
files.add(f);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
} }
} catch (Exception ex) {
fail(ex.getMessage());
} }
}; };
@ -140,12 +129,7 @@ final class Util {
r.registerListener(pfl); r.registerListener(pfl);
/* Read the POI filesystem. */ /* Read the POI filesystem. */
InputStream is = new FileInputStream(poiFs); r.read(poiFs);
try {
r.read(is);
} finally {
is.close();
}
return files; return files;
} }

View File

@ -68,7 +68,6 @@ import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream; import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.formula.ptg.Area3DPtg; import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.formula.ptg.DeletedArea3DPtg; import org.apache.poi.ss.formula.ptg.DeletedArea3DPtg;
@ -89,7 +88,6 @@ import org.apache.poi.ss.usermodel.SheetVisibility;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;
import org.junit.After;
import org.junit.Assume; import org.junit.Assume;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
@ -1022,7 +1020,7 @@ public final class TestBugs extends BaseTestBugzillaIssues {
assertEquals(4, wb.getNumberOfFontsAsInt()); assertEquals(4, wb.getNumberOfFontsAsInt());
HSSFFont f1 = wb.getFontAt((short) 0); HSSFFont f1 = wb.getFontAt(0);
assertFalse(f1.getBold()); assertFalse(f1.getBold());
// Check that asking for the same font // Check that asking for the same font
@ -1617,7 +1615,7 @@ public final class TestBugs extends BaseTestBugzillaIssues {
@Test @Test
public void bug46904() throws Exception { public void bug46904() throws Exception {
try { try {
OPOIFSFileSystem fs = new OPOIFSFileSystem( POIFSFileSystem fs = new POIFSFileSystem(
HSSFITestDataProvider.instance.openWorkbookStream("46904.xls")); HSSFITestDataProvider.instance.openWorkbookStream("46904.xls"));
new HSSFWorkbook(fs.getRoot(), false).close(); new HSSFWorkbook(fs.getRoot(), false).close();
fail("Should catch exception here"); fail("Should catch exception here");
@ -2505,7 +2503,7 @@ public final class TestBugs extends BaseTestBugzillaIssues {
@Test @Test
public void bug53432() throws IOException { public void bug53432() throws IOException {
Workbook wb1 = new HSSFWorkbook(); //or new HSSFWorkbook(); HSSFWorkbook wb1 = new HSSFWorkbook(); //or new HSSFWorkbook();
wb1.addPicture(new byte[]{123, 22}, Workbook.PICTURE_TYPE_JPEG); wb1.addPicture(new byte[]{123, 22}, Workbook.PICTURE_TYPE_JPEG);
assertEquals(wb1.getAllPictures().size(), 1); assertEquals(wb1.getAllPictures().size(), 1);
wb1.close(); wb1.close();
@ -2513,13 +2511,13 @@ public final class TestBugs extends BaseTestBugzillaIssues {
wb1.close(); wb1.close();
wb1 = new HSSFWorkbook(); wb1 = new HSSFWorkbook();
Workbook wb2 = writeOutAndReadBack((HSSFWorkbook) wb1); HSSFWorkbook wb2 = writeOutAndReadBack(wb1);
wb1.close(); wb1.close();
assertEquals(wb2.getAllPictures().size(), 0); assertEquals(wb2.getAllPictures().size(), 0);
wb2.addPicture(new byte[]{123, 22}, Workbook.PICTURE_TYPE_JPEG); wb2.addPicture(new byte[]{123, 22}, Workbook.PICTURE_TYPE_JPEG);
assertEquals(wb2.getAllPictures().size(), 1); assertEquals(wb2.getAllPictures().size(), 1);
Workbook wb3 = writeOutAndReadBack((HSSFWorkbook) wb2); HSSFWorkbook wb3 = writeOutAndReadBack(wb2);
wb2.close(); wb2.close();
assertEquals(wb3.getAllPictures().size(), 1); assertEquals(wb3.getAllPictures().size(), 1);
@ -3093,8 +3091,8 @@ public final class TestBugs extends BaseTestBugzillaIssues {
@Test @Test
public void test61287() throws IOException { public void test61287() throws IOException {
final Workbook wb = HSSFTestDataSamples.openSampleWorkbook("61287.xls"); final HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("61287.xls");
ExcelExtractor ex = new ExcelExtractor((HSSFWorkbook) wb); ExcelExtractor ex = new ExcelExtractor(wb);
String text = ex.getText(); String text = ex.getText();
assertContains(text, "\u8D44\u4EA7\u8D1F\u503A\u8868"); assertContains(text, "\u8D44\u4EA7\u8D1F\u503A\u8868");
wb.close(); wb.close();

View File

@ -29,7 +29,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -38,7 +37,6 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.hpsf.ClassID; import org.apache.poi.hpsf.ClassID;
@ -56,7 +54,6 @@ import org.apache.poi.hssf.record.WindowOneRecord;
import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.formula.ptg.Area3DPtg; import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.usermodel.BaseTestWorkbook; import org.apache.poi.ss.usermodel.BaseTestWorkbook;
@ -95,7 +92,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
/** /**
* Tests for {@link HSSFWorkbook#isHidden()} etc * Tests for {@link HSSFWorkbook#isHidden()} etc
* @throws IOException
*/ */
@Test @Test
public void hidden() throws IOException { public void hidden() throws IOException {
@ -103,23 +99,23 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
WindowOneRecord w1 = wb.getWorkbook().getWindowOne(); WindowOneRecord w1 = wb.getWorkbook().getWindowOne();
assertEquals(false, wb.isHidden()); assertFalse(wb.isHidden());
assertEquals(false, w1.getHidden()); assertFalse(w1.getHidden());
wb.setHidden(true); wb.setHidden(true);
assertEquals(true, wb.isHidden()); assertTrue(wb.isHidden());
assertEquals(true, w1.getHidden()); assertTrue(w1.getHidden());
HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb); HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb);
w1 = wbBack.getWorkbook().getWindowOne(); w1 = wbBack.getWorkbook().getWindowOne();
wbBack.setHidden(true); wbBack.setHidden(true);
assertEquals(true, wbBack.isHidden()); assertTrue(wbBack.isHidden());
assertEquals(true, w1.getHidden()); assertTrue(w1.getHidden());
wbBack.setHidden(false); wbBack.setHidden(false);
assertEquals(false, wbBack.isHidden()); assertFalse(wbBack.isHidden());
assertEquals(false, w1.getHidden()); assertFalse(w1.getHidden());
wbBack.close(); wbBack.close();
wb.close(); wb.close();
@ -257,30 +253,30 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
wb.setSelectedTabs(selected); wb.setSelectedTabs(selected);
assertCollectionsEquals(selected, wb.getSelectedTabs()); assertCollectionsEquals(selected, wb.getSelectedTabs());
assertEquals(true, sheet0.isSelected()); assertTrue(sheet0.isSelected());
assertEquals(false, sheet1.isSelected()); assertFalse(sheet1.isSelected());
assertEquals(true, sheet2.isSelected()); assertTrue(sheet2.isSelected());
assertEquals(true, sheet3.isSelected()); assertTrue(sheet3.isSelected());
assertEquals(false, sheet4.isSelected()); assertFalse(sheet4.isSelected());
assertEquals(false, sheet5.isSelected()); assertFalse(sheet5.isSelected());
selected = arrayToList(new int[] { 1, 3, 5 }); selected = arrayToList(new int[] { 1, 3, 5 });
wb.setSelectedTabs(selected); wb.setSelectedTabs(selected);
// previous selection should be cleared // previous selection should be cleared
assertCollectionsEquals(selected, wb.getSelectedTabs()); assertCollectionsEquals(selected, wb.getSelectedTabs());
assertEquals(false, sheet0.isSelected()); assertFalse(sheet0.isSelected());
assertEquals(true, sheet1.isSelected()); assertTrue(sheet1.isSelected());
assertEquals(false, sheet2.isSelected()); assertFalse(sheet2.isSelected());
assertEquals(true, sheet3.isSelected()); assertTrue(sheet3.isSelected());
assertEquals(false, sheet4.isSelected()); assertFalse(sheet4.isSelected());
assertEquals(true, sheet5.isSelected()); assertTrue(sheet5.isSelected());
assertEquals(true, sheet0.isActive()); assertTrue(sheet0.isActive());
assertEquals(false, sheet2.isActive()); assertFalse(sheet2.isActive());
wb.setActiveSheet(2); wb.setActiveSheet(2);
assertEquals(false, sheet0.isActive()); assertFalse(sheet0.isActive());
assertEquals(true, sheet2.isActive()); assertTrue(sheet2.isActive());
/*{ // helpful if viewing this workbook in excel: /*{ // helpful if viewing this workbook in excel:
sheet0.createRow(0).createCell(0).setCellValue(new HSSFRichTextString("Sheet0")); sheet0.createRow(0).createCell(0).setCellValue(new HSSFRichTextString("Sheet0"));
@ -383,7 +379,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
* records to be written with invalid offset indexes. Excel does not like this, and such * records to be written with invalid offset indexes. Excel does not like this, and such
* errors are particularly hard to track down. This test ensures that HSSFWorkbook throws * errors are particularly hard to track down. This test ensures that HSSFWorkbook throws
* a specific exception as soon as the situation is detected. See bugzilla 45066 * a specific exception as soon as the situation is detected. See bugzilla 45066
* @throws IOException
*/ */
@Test @Test
public void sheetSerializeSizeMismatch_bug45066() throws IOException { public void sheetSerializeSizeMismatch_bug45066() throws IOException {
@ -496,7 +491,7 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
* result returned by getRecordSize() differs from result returned by serialize() * result returned by getRecordSize() differs from result returned by serialize()
*/ */
private static final class BadlyBehavedRecord extends Record { private static final class BadlyBehavedRecord extends Record {
public BadlyBehavedRecord() { BadlyBehavedRecord() {
// //
} }
@Override @Override
@ -576,7 +571,7 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
POIFSFileSystem fs2 = new POIFSFileSystem(new ByteArrayInputStream(bytes)); POIFSFileSystem fs2 = new POIFSFileSystem(new ByteArrayInputStream(bytes));
ClassID clsid2 = fs2.getRoot().getStorageClsid(); ClassID clsid2 = fs2.getRoot().getStorageClsid();
assertTrue(clsid1.equals(clsid2)); assertEquals(clsid1, clsid2);
fs2.close(); fs2.close();
wb.close(); wb.close();
@ -625,108 +620,89 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
public void differentPOIFS() throws Exception { public void differentPOIFS() throws Exception {
// Open the two filesystems // Open the two filesystems
DirectoryNode[] files = new DirectoryNode[2]; DirectoryNode[] files = new DirectoryNode[2];
POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("Simple.xls")); try (POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("Simple.xls"))) {
try { files[0] = poifsFileSystem.getRoot();
files[0] = poifsFileSystem.getRoot(); try (NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("Simple.xls"))) {
NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("Simple.xls")); files[1] = npoifsFileSystem.getRoot();
try {
files[1] = npoifsFileSystem.getRoot(); // Open without preserving nodes
for (DirectoryNode dir : files) {
// Open without preserving nodes HSSFWorkbook workbook = new HSSFWorkbook(dir, false);
for(DirectoryNode dir : files) { HSSFSheet sheet = workbook.getSheetAt(0);
HSSFWorkbook workbook = new HSSFWorkbook(dir, false); HSSFCell cell = sheet.getRow(0).getCell(0);
HSSFSheet sheet = workbook.getSheetAt(0); assertEquals("replaceMe", cell.getRichStringCellValue().getString());
HSSFCell cell = sheet.getRow(0).getCell(0);
assertEquals("replaceMe", cell .getRichStringCellValue().getString()); workbook.close();
}
workbook.close();
} // Now re-check with preserving
for (DirectoryNode dir : files) {
// Now re-check with preserving HSSFWorkbook workbook = new HSSFWorkbook(dir, true);
for(DirectoryNode dir : files) { HSSFSheet sheet = workbook.getSheetAt(0);
HSSFWorkbook workbook = new HSSFWorkbook(dir, true); HSSFCell cell = sheet.getRow(0).getCell(0);
HSSFSheet sheet = workbook.getSheetAt(0); assertEquals("replaceMe", cell.getRichStringCellValue().getString());
HSSFCell cell = sheet.getRow(0).getCell(0);
assertEquals("replaceMe", cell .getRichStringCellValue().getString()); workbook.close();
}
workbook.close(); }
} }
} finally {
npoifsFileSystem.close();
}
} finally {
poifsFileSystem.close();
}
} }
@Test @Test
public void wordDocEmbeddedInXls() throws IOException { public void wordDocEmbeddedInXls() throws IOException {
// Open the two filesystems // Open the two filesystems
DirectoryNode[] files = new DirectoryNode[2]; DirectoryNode[] files = new DirectoryNode[2];
POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls")); try (POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls"))) {
try { files[0] = poifsFileSystem.getRoot();
files[0] = poifsFileSystem.getRoot(); try (NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("WithEmbeddedObjects.xls"))) {
NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("WithEmbeddedObjects.xls")); files[1] = npoifsFileSystem.getRoot();
try {
files[1] = npoifsFileSystem.getRoot(); // Check the embedded parts
for (DirectoryNode root : files) {
// Check the embedded parts HSSFWorkbook hw = new HSSFWorkbook(root, true);
for(DirectoryNode root : files) { List<HSSFObjectData> objects = hw.getAllEmbeddedObjects();
HSSFWorkbook hw = new HSSFWorkbook(root, true); boolean found = false;
List<HSSFObjectData> objects = hw.getAllEmbeddedObjects(); for (HSSFObjectData embeddedObject : objects) {
boolean found = false; if (embeddedObject.hasDirectoryEntry()) {
for (HSSFObjectData embeddedObject : objects) { DirectoryEntry dir = embeddedObject.getDirectory();
if (embeddedObject.hasDirectoryEntry()) { if (dir instanceof DirectoryNode) {
DirectoryEntry dir = embeddedObject.getDirectory(); DirectoryNode dNode = (DirectoryNode) dir;
if (dir instanceof DirectoryNode) { if (dNode.hasEntry("WordDocument")) {
DirectoryNode dNode = (DirectoryNode) dir; found = true;
if (hasEntry(dNode, "WordDocument")) { break;
found = true; }
} }
} }
} }
} assertTrue(found);
assertTrue(found);
hw.close();
hw.close(); }
} }
} finally { }
npoifsFileSystem.close();
}
} finally {
poifsFileSystem.close();
}
} }
/** /**
* Checks that we can open a workbook with NPOIFS, and write it out * Checks that we can open a workbook with NPOIFS, and write it out
* again (via POIFS) and have it be valid * again (via POIFS) and have it be valid
* @throws IOException
*/ */
@Test @Test
public void writeWorkbookFromNPOIFS() throws IOException { public void writeWorkbookFromNPOIFS() throws IOException {
InputStream is = HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls"); try (InputStream is = HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls");
try { NPOIFSFileSystem fs = new NPOIFSFileSystem(is)) {
NPOIFSFileSystem fs = new NPOIFSFileSystem(is); // Start as NPOIFS
try { HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true);
// Start as NPOIFS assertEquals(3, wb.getNumberOfSheets());
HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true); assertEquals("Root xls", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
assertEquals(3, wb.getNumberOfSheets());
assertEquals("Root xls", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
// Will switch to POIFS // Will switch to POIFS
HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb); HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb);
assertEquals(3, wbBack.getNumberOfSheets()); assertEquals(3, wbBack.getNumberOfSheets());
assertEquals("Root xls", wbBack.getSheetAt(0).getRow(0).getCell(0).getStringCellValue()); assertEquals("Root xls", wbBack.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
wbBack.close(); wbBack.close();
wb.close(); wb.close();
} finally { }
fs.close();
}
} finally {
is.close();
}
} }
@Test @Test
@ -795,7 +771,9 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
wb.setSheetOrder("other sheet", 0); wb.setSheetOrder("other sheet", 0);
// names // names
//noinspection ConstantConditions
assertEquals("'first sheet'!D1", wb.getName("name1").getRefersToFormula()); assertEquals("'first sheet'!D1", wb.getName("name1").getRefersToFormula());
//noinspection ConstantConditions
assertEquals("'other sheet'!C1", wb.getName("name2").getRefersToFormula()); assertEquals("'other sheet'!C1", wb.getName("name2").getRefersToFormula());
// cells // cells
@ -811,15 +789,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
wb.close(); wb.close();
} }
private boolean hasEntry(DirectoryNode dirNode, String entryName) {
try {
dirNode.getEntry(entryName);
return true;
} catch (FileNotFoundException e) {
return false;
}
}
@Test @Test
public void clonePictures() throws IOException { public void clonePictures() throws IOException {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithImages.xls"); HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithImages.xls");
@ -854,11 +823,8 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
// Should throw exception about invalid POIFSFileSystem // Should throw exception about invalid POIFSFileSystem
@Test(expected=IllegalArgumentException.class) @Test(expected=IllegalArgumentException.class)
public void emptyDirectoryNode() throws IOException { public void emptyDirectoryNode() throws IOException {
POIFSFileSystem fs = new POIFSFileSystem(); try (POIFSFileSystem fs = new POIFSFileSystem()) {
try {
new HSSFWorkbook(fs).close(); new HSSFWorkbook(fs).close();
} finally {
fs.close();
} }
} }
@ -1093,7 +1059,8 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
wb.close(); wb.close();
} }
private void expectName(HSSFWorkbook wb, String name, String expect) { @SuppressWarnings("SameParameterValue")
private void expectName(HSSFWorkbook wb, String name, String expect) {
final HSSFName hssfName = wb.getName(name); final HSSFName hssfName = wb.getName(name);
assertNotNull(hssfName); assertNotNull(hssfName);
assertEquals(expect, hssfName.getRefersToFormula()); assertEquals(expect, hssfName.getRefersToFormula());
@ -1149,16 +1116,13 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
// edit the workbook // edit the workbook
{ {
NPOIFSFileSystem fs = new NPOIFSFileSystem(file, false); try (NPOIFSFileSystem fs = new NPOIFSFileSystem(file, false)) {
try {
DirectoryNode root = fs.getRoot(); DirectoryNode root = fs.getRoot();
final Workbook workbook = new HSSFWorkbook(root, true); final Workbook workbook = new HSSFWorkbook(root, true);
final Sheet sheet = workbook.getSheet("foo"); final Sheet sheet = workbook.getSheet("foo");
sheet.getRow(1).createCell(2).setCellValue("baz"); sheet.getRow(1).createCell(2).setCellValue("baz");
writeAndCloseWorkbook(workbook, file); writeAndCloseWorkbook(workbook, file);
} finally {
fs.close();
} }
} }
} finally { } finally {
@ -1239,18 +1203,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
} }
wb.close(); wb.close();
// Can't work for OPOIFS
OPOIFSFileSystem ofs = new OPOIFSFileSystem(
POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SampleSS.xls"));
wb = new HSSFWorkbook(ofs.getRoot(), true);
try {
wb.write();
fail("Shouldn't work for OPOIFSFileSystem");
} catch (IllegalStateException e) {
// expected here
}
wb.close();
// Can't work for Read-Only files // Can't work for Read-Only files
NPOIFSFileSystem fs = new NPOIFSFileSystem( NPOIFSFileSystem fs = new NPOIFSFileSystem(
POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xls"), true); POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xls"), true);
@ -1268,16 +1220,9 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
public void inPlaceWrite() throws Exception { public void inPlaceWrite() throws Exception {
// Setup as a copy of a known-good file // Setup as a copy of a known-good file
final File file = TempFile.createTempFile("TestHSSFWorkbook", ".xls"); final File file = TempFile.createTempFile("TestHSSFWorkbook", ".xls");
InputStream inputStream = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SampleSS.xls"); try (InputStream inputStream = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SampleSS.xls");
try { FileOutputStream outputStream = new FileOutputStream(file)) {
FileOutputStream outputStream = new FileOutputStream(file); IOUtils.copy(inputStream, outputStream);
try {
IOUtils.copy(inputStream, outputStream);
} finally {
outputStream.close();
}
} finally {
inputStream.close();
} }
// Open from the temp file in read-write mode // Open from the temp file in read-write mode

View File

@ -17,20 +17,22 @@
package org.apache.poi.poifs.eventfilesystem; package org.apache.poi.poifs.eventfilesystem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import junit.framework.TestCase;
import org.apache.poi.poifs.filesystem.POIFSDocumentPath; import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
import org.junit.Test;
/** /**
* Class to test POIFSReaderRegistry functionality * Class to test POIFSReaderRegistry functionality
* *
* @author Marc Johnson * @author Marc Johnson
*/ */
public final class TestPOIFSReaderRegistry extends TestCase { public final class TestPOIFSReaderRegistry {
private final POIFSReaderListener[] listeners = private final POIFSReaderListener[] listeners =
{ {
new Listener(), new Listener(), new Listener(), new Listener() new Listener(), new Listener(), new Listener(), new Listener()
@ -56,13 +58,14 @@ public final class TestPOIFSReaderRegistry extends TestCase {
/** /**
* Test empty registry * Test empty registry
*/ */
@Test
public void testEmptyRegistry() { public void testEmptyRegistry() {
POIFSReaderRegistry registry = new POIFSReaderRegistry(); POIFSReaderRegistry registry = new POIFSReaderRegistry();
for (POIFSDocumentPath path : paths) { for (POIFSDocumentPath path : paths) {
for (String name : names) { for (String name : names) {
Iterator<POIFSReaderListener> listeners = Iterator<POIFSReaderListener> listeners =
registry.getListeners(path, name); registry.getListeners(path, name).iterator();
assertTrue(!listeners.hasNext()); assertTrue(!listeners.hasNext());
} }
@ -72,6 +75,7 @@ public final class TestPOIFSReaderRegistry extends TestCase {
/** /**
* Test mixed registration operations * Test mixed registration operations
*/ */
@Test
public void testMixedRegistrationOperations() { public void testMixedRegistrationOperations() {
POIFSReaderRegistry registry = new POIFSReaderRegistry(); POIFSReaderRegistry registry = new POIFSReaderRegistry();
@ -93,21 +97,20 @@ public final class TestPOIFSReaderRegistry extends TestCase {
{ {
for (int n = 0; n < names.length; n++) for (int n = 0; n < names.length; n++)
{ {
Iterator<POIFSReaderListener> listeners = Iterable<POIFSReaderListener> listeners =
registry.getListeners(paths[ k ], names[ n ]); registry.getListeners(paths[ k ], names[ n ]);
if (k == n) if (k == n)
{ {
assertTrue(!listeners.hasNext()); assertTrue(!listeners.iterator().hasNext());
} }
else else
{ {
Set<POIFSReaderListener> registeredListeners = Set<POIFSReaderListener> registeredListeners =
new HashSet<>(); new HashSet<>();
while (listeners.hasNext()) for (POIFSReaderListener rl : listeners) {
{ registeredListeners.add(rl);
registeredListeners.add(listeners.next());
} }
assertEquals(this.listeners.length - 1, assertEquals(this.listeners.length - 1,
registeredListeners.size()); registeredListeners.size());
@ -132,14 +135,13 @@ public final class TestPOIFSReaderRegistry extends TestCase {
} }
for (POIFSDocumentPath path : paths) { for (POIFSDocumentPath path : paths) {
for (String name : names) { for (String name : names) {
Iterator<POIFSReaderListener> listeners = Iterable<POIFSReaderListener> listeners =
registry.getListeners(path, name); registry.getListeners(path, name);
Set<POIFSReaderListener> registeredListeners = Set<POIFSReaderListener> registeredListeners =
new HashSet<>(); new HashSet<>();
while (listeners.hasNext()) for (POIFSReaderListener rl : listeners) {
{ registeredListeners.add(rl);
registeredListeners.add(listeners.next());
} }
assertEquals(this.listeners.length, assertEquals(this.listeners.length,
registeredListeners.size()); registeredListeners.size());

View File

@ -21,7 +21,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
/** /**
* Tests for org.apache.poi.poifs.filesystem<br> * Tests for org.apache.poi.poifs.filesystem
*/ */
@RunWith(Suite.class) @RunWith(Suite.class)
@Suite.SuiteClasses({ @Suite.SuiteClasses({
@ -29,7 +29,6 @@ import org.junit.runners.Suite;
, TestDocument.class , TestDocument.class
, TestDocumentDescriptor.class , TestDocumentDescriptor.class
, TestDocumentInputStream.class , TestDocumentInputStream.class
, TestDocumentNode.class
, TestDocumentOutputStream.class , TestDocumentOutputStream.class
, TestEmptyDocument.class , TestEmptyDocument.class
, TestNotOLE2Exception.class , TestNotOLE2Exception.class

View File

@ -19,7 +19,7 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import java.io.FileInputStream; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -38,42 +38,19 @@ import org.apache.poi.util.IOUtils;
* @author Marc Johnson (mjohnson at apache dot org) * @author Marc Johnson (mjohnson at apache dot org)
*/ */
public class ReaderWriter public final class ReaderWriter
implements POIFSReaderListener, POIFSWriterListener implements POIFSReaderListener, POIFSWriterListener
{ {
private final POIFSFileSystem filesystem;
private final DirectoryEntry root; private final DirectoryEntry root;
// keys are DocumentDescriptors, values are byte[]s // keys are DocumentDescriptors, values are byte[]s
private final Map<DocumentDescriptor, byte[]> dataMap; private final Map<DocumentDescriptor, byte[]> dataMap = new HashMap<>();
/** private ReaderWriter(final POIFSFileSystem filesystem) {
* Constructor ReaderWriter root = filesystem.getRoot();
*
*
* @param filesystem
*
*/
ReaderWriter(final POIFSFileSystem filesystem)
{
this.filesystem = filesystem;
root = this.filesystem.getRoot();
dataMap = new HashMap<>();
} }
/** public static void main(String [] args) throws IOException
* Method main
*
*
* @param args
*
* @exception IOException
*
*/
public static void main(String [] args)
throws IOException
{ {
if (args.length != 2) if (args.length != 2)
{ {
@ -86,10 +63,8 @@ public class ReaderWriter
POIFSFileSystem filesystem = new POIFSFileSystem(); POIFSFileSystem filesystem = new POIFSFileSystem();
reader.registerListener(new ReaderWriter(filesystem)); reader.registerListener(new ReaderWriter(filesystem));
FileInputStream istream = new FileInputStream(args[ 0 ]);
reader.read(istream); reader.read(new File(args[ 0 ]));
istream.close();
FileOutputStream ostream = new FileOutputStream(args[ 1 ]); FileOutputStream ostream = new FileOutputStream(args[ 1 ]);
filesystem.writeFilesystem(ostream); filesystem.writeFilesystem(ostream);

View File

@ -17,218 +17,131 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static org.apache.poi.poifs.common.POIFSConstants.LARGER_BIG_BLOCK_SIZE;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.stream.IntStream;
import org.apache.poi.poifs.property.DocumentProperty; import org.apache.poi.poifs.property.DocumentProperty;
import org.apache.poi.poifs.storage.RawDataBlock; import org.apache.poi.poifs.storage.RawDataUtil;
import org.apache.poi.util.IOUtils;
import junit.framework.TestCase; import org.junit.Test;
/** /**
* Class to test OPOIFSDocument functionality * Class to test POIFSDocument functionality
*/ */
public final class TestDocument extends TestCase { public class TestDocument {
/** /**
* Integration test -- really about all we can do * Integration test -- really about all we can do
*/ */
public void testOPOIFSDocument() throws IOException { @Test
public void testNPOIFSDocument() throws IOException {
// verify correct number of blocks get created for document try (NPOIFSFileSystem poifs = new NPOIFSFileSystem()) {
// that is exact multituple of block size
OPOIFSDocument document;
byte[] array = new byte[ 4096 ];
for (int j = 0; j < array.length; j++) // verify correct number of blocks get created for document
{ // that is exact multiple of block size
array[ j ] = ( byte ) j; checkDocument(poifs, LARGER_BIG_BLOCK_SIZE);
}
document = new OPOIFSDocument("foo", new SlowInputStream(new ByteArrayInputStream(array)));
checkDocument(document, array);
// verify correct number of blocks get created for document // verify correct number of blocks get created for document
// that is not an exact multiple of block size // that is not an exact multiple of block size
array = new byte[ 4097 ]; checkDocument(poifs, LARGER_BIG_BLOCK_SIZE + 1);
for (int j = 0; j < array.length; j++)
{
array[ j ] = ( byte ) j;
}
document = new OPOIFSDocument("bar", new ByteArrayInputStream(array));
checkDocument(document, array);
// verify correct number of blocks get created for document // verify correct number of blocks get created for document
// that is small // that is small
array = new byte[ 4095 ]; checkDocument(poifs, LARGER_BIG_BLOCK_SIZE - 1);
for (int j = 0; j < array.length; j++)
{
array[ j ] = ( byte ) j;
}
document = new OPOIFSDocument("_bar", new ByteArrayInputStream(array));
checkDocument(document, array);
// verify correct number of blocks get created for document // verify correct number of blocks get created for document
// that is rather small // that is rather small
array = new byte[ 199 ]; checkDocument(poifs, 199);
for (int j = 0; j < array.length; j++)
{
array[ j ] = ( byte ) j;
}
document = new OPOIFSDocument("_bar2",
new ByteArrayInputStream(array));
checkDocument(document, array);
// verify that output is correct
array = new byte[ 4097 ];
for (int j = 0; j < array.length; j++)
{
array[ j ] = ( byte ) j;
}
document = new OPOIFSDocument("foobar",
new ByteArrayInputStream(array));
checkDocument(document, array);
document.setStartBlock(0x12345678); // what a big file!!
DocumentProperty property = document.getDocumentProperty();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
property.writeData(stream); // verify that output is correct
byte[] output = stream.toByteArray(); NPOIFSDocument document = checkDocument(poifs, LARGER_BIG_BLOCK_SIZE + 1);
byte[] array2 = DocumentProperty property = document.getDocumentProperty();
{ ByteArrayOutputStream stream = new ByteArrayOutputStream();
( byte ) 'f', ( byte ) 0, ( byte ) 'o', ( byte ) 0, ( byte ) 'o',
( byte ) 0, ( byte ) 'b', ( byte ) 0, ( byte ) 'a', ( byte ) 0,
( byte ) 'r', ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 14,
( byte ) 0, ( byte ) 2, ( byte ) 1, ( byte ) -1, ( byte ) -1,
( byte ) -1, ( byte ) -1, ( byte ) -1, ( byte ) -1, ( byte ) -1,
( byte ) -1, ( byte ) -1, ( byte ) -1, ( byte ) -1, ( byte ) -1,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0x78, ( byte ) 0x56, ( byte ) 0x34,
( byte ) 0x12, ( byte ) 1, ( byte ) 16, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0
};
assertEquals(array2.length, output.length); property.writeData(stream);
for (int j = 0; j < output.length; j++) byte[] output = stream.toByteArray();
{ byte[] array2 = RawDataUtil.decompress("H4sIAAAAAAAAAEtlyGMoYShiqGSwYCAH8DEwMf5HAsToMQdiRgEIGwCDyzEQgAAAAA==");
assertEquals("Checking property offset " + j, array2[ j ],
output[ j ]); assertArrayEquals(array2, output);
} }
} }
private static OPOIFSDocument makeCopy(OPOIFSDocument document, byte[] input, byte[] data) private static NPOIFSDocument checkDocument(final NPOIFSFileSystem poifs, final int size) throws IOException {
throws IOException { final byte[] input = new byte[size];
OPOIFSDocument copy = null; IntStream.range(0, size).forEach(i -> input[i] = (byte)i);
if (input.length >= 4096) NPOIFSDocument document = ((DocumentNode)poifs.createDocument(
{ new SlowInputStream(new ByteArrayInputStream(input)),
RawDataBlock[] blocks = "entry"+poifs.getRoot().getEntryCount())).getDocument();
new RawDataBlock[ (input.length + 511) / 512 ];
ByteArrayInputStream stream = new ByteArrayInputStream(data);
int index = 0;
while (true) final int blockSize = (size >= 4096) ? 512 : 64;
{ final int blockCount = (size + (blockSize-1)) / blockSize;
RawDataBlock block = new RawDataBlock(stream);
if (block.eof()) final byte[] bytCpy = checkValues(blockCount, document, input);
{ final NPOIFSDocument copied = makeCopy(document,bytCpy);
break;
} checkValues(blockCount, copied, input);
blocks[ index++ ] = block;
} return document;
copy = new OPOIFSDocument("test" + input.length, blocks,
input.length);
}
else
{
copy = new OPOIFSDocument("test"+input.length, document.getSmallBlocks(), input.length);
}
return copy;
} }
private static void checkDocument(final OPOIFSDocument document, final byte[] input) private static NPOIFSDocument makeCopy(NPOIFSDocument document, byte[] input) throws IOException {
throws IOException { NPOIFSFileSystem poifs = document.getFileSystem();
int big_blocks = 0; String name = "test" + input.length;
int small_blocks = 0; DirectoryNode root = poifs.getRoot();
int total_output = 0; if (root.hasEntry(name)) {
root.deleteEntry((EntryNode)root.getEntry(name));
if (input.length >= 4096)
{
big_blocks = (input.length + 511) / 512;
total_output = big_blocks * 512;
} }
else return ((DocumentNode)root
{ .createDocument(name, new ByteArrayInputStream(input)))
small_blocks = (input.length + 63) / 64; .getDocument();
total_output = 0;
}
checkValues(
big_blocks, small_blocks, total_output,
makeCopy(
document, input,
checkValues(
big_blocks, small_blocks, total_output, document,
input)), input);
} }
private static byte[] checkValues(int big_blocks, int small_blocks, int total_output, private static byte[] checkValues(final int blockCountExp, NPOIFSDocument document, byte[] input) throws IOException {
OPOIFSDocument document, byte[] input) throws IOException { assertNotNull(document);
assertNotNull(document.getDocumentProperty().getDocument());
assertEquals(document, document.getDocumentProperty().getDocument()); assertEquals(document, document.getDocumentProperty().getDocument());
int increment = ( int ) Math.sqrt(input.length);
for (int j = 1; j <= input.length; j += increment) ByteArrayInputStream bis = new ByteArrayInputStream(input);
{
byte[] buffer = new byte[ j ];
int offset = 0;
for (int k = 0; k < (input.length / j); k++) int blockCountAct = 0, bytesRemaining = input.length;
{ for (ByteBuffer bb : document) {
document.read(buffer, offset); assertTrue(bytesRemaining > 0);
for (int n = 0; n < buffer.length; n++) int bytesAct = Math.min(bb.remaining(), bytesRemaining);
{ assertTrue(bytesAct <= document.getDocumentBlockSize());
assertEquals("checking byte " + (k * j) + n, byte[] bufAct = new byte[bytesAct];
input[ (k * j) + n ], buffer[ n ]); bb.get(bufAct);
}
offset += j; byte[] bufExp = new byte[bytesAct];
} int bytesExp = bis.read(bufExp, 0, bytesAct);
assertEquals(bytesExp, bytesAct);
assertArrayEquals(bufExp, bufAct);
blockCountAct++;
bytesRemaining -= bytesAct;
} }
assertEquals(big_blocks, document.countBlocks());
assertEquals(small_blocks, document.getSmallBlocks().length); assertEquals(blockCountExp, blockCountAct);
ByteArrayOutputStream stream = new ByteArrayOutputStream(); ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (DocumentInputStream dis = document.getFileSystem().createDocumentInputStream(
document.getDocumentProperty().getName())) {
IOUtils.copy(dis, stream);
}
document.writeBlocks(stream);
byte[] output = stream.toByteArray(); byte[] output = stream.toByteArray();
assertArrayEquals(input, stream.toByteArray());
assertEquals(total_output, output.length);
int limit = Math.min(total_output, input.length);
for (int j = 0; j < limit; j++)
{
assertEquals("Checking document offset " + j, input[ j ],
output[ j ]);
}
for (int j = limit; j < output.length; j++)
{
assertEquals("Checking document offset " + j, ( byte ) -1,
output[ j ]);
}
return output; return output;
} }
} }

View File

@ -18,19 +18,17 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.storage.RawDataBlock;
import org.apache.poi.util.SuppressForbidden; import org.apache.poi.util.SuppressForbidden;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -39,448 +37,369 @@ import org.junit.Test;
* Class to test DocumentInputStream functionality * Class to test DocumentInputStream functionality
*/ */
public final class TestDocumentInputStream { public final class TestDocumentInputStream {
private DocumentNode _workbook_n; private DocumentNode _workbook_n;
private DocumentNode _workbook_o; private byte[] _workbook_data;
private byte[] _workbook_data; private static final int _workbook_size = 5000;
private static final int _workbook_size = 5000;
// non-even division of _workbook_size, also non-even division of // non-even division of _workbook_size, also non-even division of
// any block size // any block size
private static final int _buffer_size = 6; private static final int _buffer_size = 6;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
int blocks = (_workbook_size + 511) / 512; int blocks = (_workbook_size + 511) / 512;
_workbook_data = new byte[ 512 * blocks ]; _workbook_data = new byte[512 * blocks];
Arrays.fill(_workbook_data, ( byte ) -1); Arrays.fill(_workbook_data, (byte) -1);
for (int j = 0; j < _workbook_size; j++) for (int j = 0; j < _workbook_size; j++) {
{ _workbook_data[j] = (byte) (j * j);
_workbook_data[ j ] = ( byte ) (j * j);
} }
// Create the Old POIFS Version
RawDataBlock[] rawBlocks = new RawDataBlock[ blocks ];
ByteArrayInputStream stream =
new ByteArrayInputStream(_workbook_data);
for (int j = 0; j < blocks; j++)
{
rawBlocks[ j ] = new RawDataBlock(stream);
}
OPOIFSDocument document = new OPOIFSDocument("Workbook", rawBlocks,
_workbook_size);
_workbook_o = new DocumentNode(
document.getDocumentProperty(),
new DirectoryNode(
new DirectoryProperty("Root Entry"), (POIFSFileSystem)null, null));
// Now create the NPOIFS Version // Now create the NPOIFS Version
byte[] _workbook_data_only = new byte[_workbook_size]; byte[] _workbook_data_only = new byte[_workbook_size];
System.arraycopy(_workbook_data, 0, _workbook_data_only, 0, _workbook_size); System.arraycopy(_workbook_data, 0, _workbook_data_only, 0, _workbook_size);
NPOIFSFileSystem npoifs = new NPOIFSFileSystem(); NPOIFSFileSystem npoifs = new NPOIFSFileSystem();
// Make it easy when debugging to see what isn't the doc // Make it easy when debugging to see what isn't the doc
byte[] minus1 = new byte[512]; byte[] minus1 = new byte[512];
Arrays.fill(minus1, (byte)-1); Arrays.fill(minus1, (byte) -1);
npoifs.getBlockAt(-1).put(minus1); npoifs.getBlockAt(-1).put(minus1);
npoifs.getBlockAt(0).put(minus1); npoifs.getBlockAt(0).put(minus1);
npoifs.getBlockAt(1).put(minus1); npoifs.getBlockAt(1).put(minus1);
// Create the NPOIFS document // Create the NPOIFS document
_workbook_n = (DocumentNode)npoifs.createDocument( _workbook_n = (DocumentNode) npoifs.createDocument(
new ByteArrayInputStream(_workbook_data_only), new ByteArrayInputStream(_workbook_data_only),
"Workbook" "Workbook"
); );
} }
/** /**
* test constructor * test constructor
*/ */
@Test @Test
public void testConstructor() throws IOException { public void testConstructor() throws IOException {
DocumentInputStream ostream = new ODocumentInputStream(_workbook_o); try (DocumentInputStream nstream = new NDocumentInputStream(_workbook_n)) {
DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); assertEquals(_workbook_size, _workbook_n.getSize());
assertEquals(_workbook_size, available(nstream));
assertEquals(_workbook_size, _workbook_o.getSize()); }
assertEquals(_workbook_size, _workbook_n.getSize());
assertEquals(_workbook_size, available(ostream));
assertEquals(_workbook_size, available(nstream));
ostream.close();
nstream.close();
} }
/** /**
* test available() behavior * test available() behavior
*/ */
@Test @Test(expected = IllegalStateException.class)
public void testAvailable() throws IOException { public void testAvailable() throws IOException {
DocumentInputStream ostream = new DocumentInputStream(_workbook_o);
DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); DocumentInputStream nstream = new NDocumentInputStream(_workbook_n);
assertEquals(_workbook_size, available(ostream));
assertEquals(_workbook_size, available(nstream)); assertEquals(_workbook_size, available(nstream));
ostream.close();
nstream.close(); nstream.close();
try { available(nstream);
available(ostream);
fail("Should have caught IOException");
} catch (IllegalStateException ignored) {
// as expected
}
try {
available(nstream);
fail("Should have caught IOException");
} catch (IllegalStateException ignored) {
// as expected
}
} }
/** /**
* test mark/reset/markSupported. * test mark/reset/markSupported.
*/ */
@SuppressWarnings("ResultOfMethodCallIgnored")
@Test @Test
public void testMarkFunctions() throws IOException { public void testMarkFunctions() throws IOException {
byte[] buffer = new byte[ _workbook_size / 5 ]; byte[] buffer = new byte[_workbook_size / 5];
byte[] small_buffer = new byte[212]; byte[] small_buffer = new byte[212];
DocumentInputStream[] streams = new DocumentInputStream[] { DocumentInputStream stream = new NDocumentInputStream(_workbook_n);
new DocumentInputStream(_workbook_o), // Read a fifth of it, and check all's correct
new NDocumentInputStream(_workbook_n) stream.read(buffer);
}; for (int j = 0; j < buffer.length; j++) {
for(DocumentInputStream stream : streams) { assertEquals(
// Read a fifth of it, and check all's correct "checking byte " + j,
stream.read(buffer); _workbook_data[j], buffer[j]
for (int j = 0; j < buffer.length; j++) { );
assertEquals(
"checking byte " + j,
_workbook_data[ j ], buffer[ j ]
);
}
assertEquals(_workbook_size - buffer.length, available(stream));
// Reset, and check the available goes back to being the
// whole of the stream
stream.reset();
assertEquals(_workbook_size, available(stream));
// Read part of a block
stream.read(small_buffer);
for (int j = 0; j < small_buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[ j ], small_buffer[ j ]
);
}
assertEquals(_workbook_size - small_buffer.length, available(stream));
stream.mark(0);
// Read the next part
stream.read(small_buffer);
for (int j = 0; j < small_buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[ j+small_buffer.length ], small_buffer[ j ]
);
}
assertEquals(_workbook_size - 2*small_buffer.length, available(stream));
// Reset, check it goes back to where it was
stream.reset();
assertEquals(_workbook_size - small_buffer.length, available(stream));
// Read
stream.read(small_buffer);
for (int j = 0; j < small_buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[ j+small_buffer.length ], small_buffer[ j ]
);
}
assertEquals(_workbook_size - 2*small_buffer.length, available(stream));
// Now read at various points
Arrays.fill(small_buffer, ( byte ) 0);
stream.read(small_buffer, 6, 8);
stream.read(small_buffer, 100, 10);
stream.read(small_buffer, 150, 12);
int pos = small_buffer.length * 2;
for (int j = 0; j < small_buffer.length; j++) {
byte exp = 0;
if(j>= 6 && j<6+8) {
exp = _workbook_data[pos];
pos++;
}
if(j>= 100 && j<100+10) {
exp = _workbook_data[pos];
pos++;
}
if(j>= 150 && j<150+12) {
exp = _workbook_data[pos];
pos++;
}
assertEquals("checking byte " + j, exp, small_buffer[j]);
}
} }
assertEquals(_workbook_size - buffer.length, available(stream));
// Reset, and check the available goes back to being the
// whole of the stream
stream.reset();
assertEquals(_workbook_size, available(stream));
// Read part of a block
stream.read(small_buffer);
for (int j = 0; j < small_buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[j], small_buffer[j]
);
}
assertEquals(_workbook_size - small_buffer.length, available(stream));
stream.mark(0);
// Read the next part
stream.read(small_buffer);
for (int j = 0; j < small_buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[j + small_buffer.length], small_buffer[j]
);
}
assertEquals(_workbook_size - 2 * small_buffer.length, available(stream));
// Reset, check it goes back to where it was
stream.reset();
assertEquals(_workbook_size - small_buffer.length, available(stream));
// Read
stream.read(small_buffer);
for (int j = 0; j < small_buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[j + small_buffer.length], small_buffer[j]
);
}
assertEquals(_workbook_size - 2 * small_buffer.length, available(stream));
// Now read at various points
Arrays.fill(small_buffer, (byte) 0);
stream.read(small_buffer, 6, 8);
stream.read(small_buffer, 100, 10);
stream.read(small_buffer, 150, 12);
int pos = small_buffer.length * 2;
for (int j = 0; j < small_buffer.length; j++) {
byte exp = 0;
if (j >= 6 && j < 6 + 8) {
exp = _workbook_data[pos];
pos++;
}
if (j >= 100 && j < 100 + 10) {
exp = _workbook_data[pos];
pos++;
}
if (j >= 150 && j < 150 + 12) {
exp = _workbook_data[pos];
pos++;
}
assertEquals("checking byte " + j, exp, small_buffer[j]);
}
// Now repeat it with spanning multiple blocks // Now repeat it with spanning multiple blocks
streams = new DocumentInputStream[] { stream = new NDocumentInputStream(_workbook_n);
new DocumentInputStream(_workbook_o), // Read several blocks work
new NDocumentInputStream(_workbook_n) buffer = new byte[_workbook_size / 5];
}; stream.read(buffer);
for(DocumentInputStream stream : streams) { for (int j = 0; j < buffer.length; j++) {
// Read several blocks work assertEquals(
buffer = new byte[ _workbook_size / 5 ]; "checking byte " + j,
stream.read(buffer); _workbook_data[j], buffer[j]
for (int j = 0; j < buffer.length; j++) { );
assertEquals(
"checking byte " + j,
_workbook_data[ j ], buffer[ j ]
);
}
assertEquals(_workbook_size - buffer.length, available(stream));
// Read all of it again, check it began at the start again
stream.reset();
assertEquals(_workbook_size, available(stream));
stream.read(buffer);
for (int j = 0; j < buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[ j ], buffer[ j ]
);
}
// Mark our position, and read another whole buffer
stream.mark(12);
stream.read(buffer);
assertEquals(_workbook_size - (2 * buffer.length),
available(stream));
for (int j = buffer.length; j < (2 * buffer.length); j++)
{
assertEquals("checking byte " + j, _workbook_data[ j ],
buffer[ j - buffer.length ]);
}
// Reset, should go back to only one buffer full read
stream.reset();
assertEquals(_workbook_size - buffer.length, available(stream));
// Read the buffer again
stream.read(buffer);
assertEquals(_workbook_size - (2 * buffer.length),
available(stream));
for (int j = buffer.length; j < (2 * buffer.length); j++)
{
assertEquals("checking byte " + j, _workbook_data[ j ],
buffer[ j - buffer.length ]);
}
assertTrue(stream.markSupported());
} }
assertEquals(_workbook_size - buffer.length, available(stream));
// Read all of it again, check it began at the start again
stream.reset();
assertEquals(_workbook_size, available(stream));
stream.read(buffer);
for (int j = 0; j < buffer.length; j++) {
assertEquals(
"checking byte " + j,
_workbook_data[j], buffer[j]
);
}
// Mark our position, and read another whole buffer
stream.mark(12);
stream.read(buffer);
assertEquals(_workbook_size - (2 * buffer.length),
available(stream));
for (int j = buffer.length; j < (2 * buffer.length); j++) {
assertEquals("checking byte " + j, _workbook_data[j],
buffer[j - buffer.length]);
}
// Reset, should go back to only one buffer full read
stream.reset();
assertEquals(_workbook_size - buffer.length, available(stream));
// Read the buffer again
stream.read(buffer);
assertEquals(_workbook_size - (2 * buffer.length),
available(stream));
for (int j = buffer.length; j < (2 * buffer.length); j++) {
assertEquals("checking byte " + j, _workbook_data[j],
buffer[j - buffer.length]);
}
assertTrue(stream.markSupported());
} }
/** /**
* test simple read method * test simple read method
*/ */
@Test @SuppressWarnings("ResultOfMethodCallIgnored")
@Test(expected = IOException.class)
public void testReadSingleByte() throws IOException { public void testReadSingleByte() throws IOException {
DocumentInputStream[] streams = new DocumentInputStream[] { DocumentInputStream stream = new NDocumentInputStream(_workbook_n);
new DocumentInputStream(_workbook_o), int remaining = _workbook_size;
new NDocumentInputStream(_workbook_n)
};
for(DocumentInputStream stream : streams) {
int remaining = _workbook_size;
// Try and read each byte in turn // Try and read each byte in turn
for (int j = 0; j < _workbook_size; j++) { for (int j = 0; j < _workbook_size; j++) {
int b = stream.read(); int b = stream.read();
assertTrue("checking sign of " + j, b >= 0); assertTrue("checking sign of " + j, b >= 0);
assertEquals("validating byte " + j, _workbook_data[ j ], assertEquals("validating byte " + j, _workbook_data[j],
( byte ) b); (byte) b);
remaining--; remaining--;
assertEquals("checking remaining after reading byte " + j, assertEquals("checking remaining after reading byte " + j,
remaining, available(stream)); remaining, available(stream));
} }
// Ensure we fell off the end // Ensure we fell off the end
assertEquals(-1, stream.read()); assertEquals(-1, stream.read());
// Check that after close we can no longer read // Check that after close we can no longer read
stream.close(); stream.close();
try { stream.read();
stream.read();
fail("Should have caught IOException");
} catch (IOException ignored) {
// as expected
}
}
} }
/** /**
* Test buffered read * Test buffered read
*/ */
@SuppressWarnings("ResultOfMethodCallIgnored")
@Test @Test
public void testBufferRead() throws IOException { public void testBufferRead() throws IOException {
DocumentInputStream[] streams = new DocumentInputStream[] { DocumentInputStream stream = new NDocumentInputStream(_workbook_n);
new DocumentInputStream(_workbook_o), // Need to give a byte array to read
new NDocumentInputStream(_workbook_n) try {
}; stream.read(null);
for(DocumentInputStream stream : streams) { fail("Should have caught NullPointerException");
// Need to give a byte array to read } catch (NullPointerException ignored) {
try { // as expected
stream.read(null); }
fail("Should have caught NullPointerException");
} catch (NullPointerException ignored) {
// as expected
}
// test reading zero length buffer // test reading zero length buffer
assertEquals(0, stream.read(new byte[ 0 ])); assertEquals(0, stream.read(new byte[0]));
assertEquals(_workbook_size, available(stream)); assertEquals(_workbook_size, available(stream));
byte[] buffer = new byte[ _buffer_size ]; byte[] buffer = new byte[_buffer_size];
int offset = 0; int offset = 0;
while (available(stream) >= buffer.length) while (available(stream) >= buffer.length) {
{ assertEquals(_buffer_size, stream.read(buffer));
assertEquals(_buffer_size, stream.read(buffer)); for (byte element : buffer) {
for (byte element : buffer) {
assertEquals("in main loop, byte " + offset, assertEquals("in main loop, byte " + offset,
_workbook_data[ offset ], element); _workbook_data[offset], element);
offset++; offset++;
} }
assertEquals("offset " + offset, _workbook_size - offset, assertEquals("offset " + offset, _workbook_size - offset,
available(stream)); available(stream));
} }
assertEquals(_workbook_size % _buffer_size, available(stream)); assertEquals(_workbook_size % _buffer_size, available(stream));
Arrays.fill(buffer, ( byte ) 0); Arrays.fill(buffer, (byte) 0);
int count = stream.read(buffer); int count = stream.read(buffer);
assertEquals(_workbook_size % _buffer_size, count); assertEquals(_workbook_size % _buffer_size, count);
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++) {
{ assertEquals("past main loop, byte " + offset,
assertEquals("past main loop, byte " + offset, _workbook_data[offset], buffer[j]);
_workbook_data[ offset ], buffer[ j ]); offset++;
offset++; }
} assertEquals(_workbook_size, offset);
assertEquals(_workbook_size, offset); for (int j = count; j < buffer.length; j++) {
for (int j = count; j < buffer.length; j++) assertEquals("checking remainder, byte " + j, 0, buffer[j]);
{ }
assertEquals("checking remainder, byte " + j, 0, buffer[ j ]); assertEquals(-1, stream.read(buffer));
} stream.close();
assertEquals(-1, stream.read(buffer)); try {
stream.close(); stream.read(buffer);
try { fail("Should have caught IOException");
stream.read(buffer); } catch (IOException ignored) {
fail("Should have caught IOException"); // as expected
} catch (IOException ignored) { }
// as expected
}
}
} }
/** /**
* Test complex buffered read * Test complex buffered read
*/ */
@SuppressWarnings("ResultOfMethodCallIgnored")
@Test @Test
public void testComplexBufferRead() throws IOException { public void testComplexBufferRead() throws IOException {
DocumentInputStream[] streams = new DocumentInputStream[] { DocumentInputStream stream = new NDocumentInputStream(_workbook_n);
new DocumentInputStream(_workbook_o), try {
new NDocumentInputStream(_workbook_n) stream.read(null, 0, 1);
}; fail("Should have caught NullPointerException");
for(DocumentInputStream stream : streams) { } catch (IllegalArgumentException ignored) {
try { // as expected
stream.read(null, 0, 1); }
fail("Should have caught NullPointerException");
} catch (IllegalArgumentException ignored) {
// as expected
}
// test illegal offsets and lengths // test illegal offsets and lengths
try { try {
stream.read(new byte[ 5 ], -4, 0); stream.read(new byte[5], -4, 0);
fail("Should have caught IndexOutOfBoundsException"); fail("Should have caught IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException ignored) { } catch (IndexOutOfBoundsException ignored) {
// as expected // as expected
} }
try { try {
stream.read(new byte[ 5 ], 0, -4); stream.read(new byte[5], 0, -4);
fail("Should have caught IndexOutOfBoundsException"); fail("Should have caught IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException ignored) { } catch (IndexOutOfBoundsException ignored) {
// as expected // as expected
} }
try { try {
stream.read(new byte[ 5 ], 0, 6); stream.read(new byte[5], 0, 6);
fail("Should have caught IndexOutOfBoundsException"); fail("Should have caught IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException ignored) { } catch (IndexOutOfBoundsException ignored) {
// as expected // as expected
} }
// test reading zero // test reading zero
assertEquals(0, stream.read(new byte[ 5 ], 0, 0)); assertEquals(0, stream.read(new byte[5], 0, 0));
assertEquals(_workbook_size, available(stream)); assertEquals(_workbook_size, available(stream));
byte[] buffer = new byte[ _workbook_size ]; byte[] buffer = new byte[_workbook_size];
int offset = 0; int offset = 0;
while (available(stream) >= _buffer_size) while (available(stream) >= _buffer_size) {
{ Arrays.fill(buffer, (byte) 0);
Arrays.fill(buffer, ( byte ) 0); assertEquals(_buffer_size,
assertEquals(_buffer_size, stream.read(buffer, offset, _buffer_size));
stream.read(buffer, offset, _buffer_size)); for (int j = 0; j < offset; j++) {
for (int j = 0; j < offset; j++) assertEquals("checking byte " + j, 0, buffer[j]);
{ }
assertEquals("checking byte " + j, 0, buffer[ j ]); for (int j = offset; j < (offset + _buffer_size); j++) {
} assertEquals("checking byte " + j, _workbook_data[j],
for (int j = offset; j < (offset + _buffer_size); j++) buffer[j]);
{ }
assertEquals("checking byte " + j, _workbook_data[ j ], for (int j = offset + _buffer_size; j < buffer.length; j++) {
buffer[ j ]); assertEquals("checking byte " + j, 0, buffer[j]);
} }
for (int j = offset + _buffer_size; j < buffer.length; j++) offset += _buffer_size;
{ assertEquals("offset " + offset, _workbook_size - offset,
assertEquals("checking byte " + j, 0, buffer[ j ]); available(stream));
} }
offset += _buffer_size; assertEquals(_workbook_size % _buffer_size, available(stream));
assertEquals("offset " + offset, _workbook_size - offset, Arrays.fill(buffer, (byte) 0);
available(stream)); int count = stream.read(buffer, offset,
}
assertEquals(_workbook_size % _buffer_size, available(stream));
Arrays.fill(buffer, ( byte ) 0);
int count = stream.read(buffer, offset,
_workbook_size % _buffer_size); _workbook_size % _buffer_size);
assertEquals(_workbook_size % _buffer_size, count); assertEquals(_workbook_size % _buffer_size, count);
for (int j = 0; j < offset; j++) for (int j = 0; j < offset; j++) {
{ assertEquals("checking byte " + j, 0, buffer[j]);
assertEquals("checking byte " + j, 0, buffer[ j ]); }
} for (int j = offset; j < buffer.length; j++) {
for (int j = offset; j < buffer.length; j++) assertEquals("checking byte " + j, _workbook_data[j],
{ buffer[j]);
assertEquals("checking byte " + j, _workbook_data[ j ], }
buffer[ j ]); assertEquals(_workbook_size, offset + count);
} for (int j = count; j < offset; j++) {
assertEquals(_workbook_size, offset + count); assertEquals("byte " + j, 0, buffer[j]);
for (int j = count; j < offset; j++) }
{
assertEquals("byte " + j, 0, buffer[ j ]); assertEquals(-1, stream.read(buffer, 0, 1));
} stream.close();
try {
assertEquals(-1, stream.read(buffer, 0, 1)); stream.read(buffer, 0, 1);
stream.close(); fail("Should have caught IOException");
try { } catch (IOException ignored) {
stream.read(buffer, 0, 1); // as expected
fail("Should have caught IOException"); }
} catch (IOException ignored) {
// as expected
}
}
} }
/** /**
@ -488,82 +407,67 @@ public final class TestDocumentInputStream {
*/ */
@Test @Test
public void testSkip() throws IOException { public void testSkip() throws IOException {
DocumentInputStream[] streams = new DocumentInputStream[] { DocumentInputStream stream = new NDocumentInputStream(_workbook_n);
new DocumentInputStream(_workbook_o), assertEquals(_workbook_size, available(stream));
new NDocumentInputStream(_workbook_n) int count = available(stream);
};
for(DocumentInputStream stream : streams) {
assertEquals(_workbook_size, available(stream));
int count = available(stream);
while (available(stream) >= _buffer_size) { while (available(stream) >= _buffer_size) {
assertEquals(_buffer_size, stream.skip(_buffer_size)); assertEquals(_buffer_size, stream.skip(_buffer_size));
count -= _buffer_size; count -= _buffer_size;
assertEquals(count, available(stream)); assertEquals(count, available(stream));
} }
assertEquals(_workbook_size % _buffer_size, assertEquals(_workbook_size % _buffer_size,
stream.skip(_buffer_size)); stream.skip(_buffer_size));
assertEquals(0, available(stream)); assertEquals(0, available(stream));
stream.reset(); stream.reset();
assertEquals(_workbook_size, available(stream)); assertEquals(_workbook_size, available(stream));
assertEquals(_workbook_size, stream.skip(_workbook_size * 2)); assertEquals(_workbook_size, stream.skip(_workbook_size * 2));
assertEquals(0, available(stream)); assertEquals(0, available(stream));
stream.reset(); stream.reset();
assertEquals(_workbook_size, available(stream)); assertEquals(_workbook_size, available(stream));
assertEquals(_workbook_size, assertEquals(_workbook_size,
stream.skip(2 + ( long ) Integer.MAX_VALUE)); stream.skip(2 + (long) Integer.MAX_VALUE));
assertEquals(0, available(stream)); assertEquals(0, available(stream));
}
} }
/** /**
* Test that we can read files at multiple levels down the tree * Test that we can read files at multiple levels down the tree
*/ */
@Test @Test
public void testReadMultipleTreeLevels() throws Exception { public void testReadMultipleTreeLevels() throws Exception {
final POIDataSamples _samples = POIDataSamples.getPublisherInstance(); final POIDataSamples _samples = POIDataSamples.getPublisherInstance();
File sample = _samples.getFile("Sample.pub"); File sample = _samples.getFile("Sample.pub");
DocumentInputStream stream; DocumentInputStream stream;
NPOIFSFileSystem npoifs = new NPOIFSFileSystem(sample); try (NPOIFSFileSystem npoifs = new NPOIFSFileSystem(sample)) {
try { // Ensure we have what we expect on the root
OPOIFSFileSystem opoifs = new OPOIFSFileSystem(new FileInputStream(sample)); assertEquals(npoifs, npoifs.getRoot().getNFileSystem());
assertEquals(npoifs, npoifs.getRoot().getFileSystem());
// Ensure we have what we expect on the root
assertEquals(npoifs, npoifs.getRoot().getNFileSystem()); // Check inside
assertEquals(npoifs, npoifs.getRoot().getFileSystem()); DirectoryNode root = npoifs.getRoot();
assertEquals(null, npoifs.getRoot().getOFileSystem()); // Top Level
assertEquals(null, opoifs.getRoot().getFileSystem()); Entry top = root.getEntry("Contents");
assertEquals(opoifs, opoifs.getRoot().getOFileSystem()); assertTrue(top.isDocumentEntry());
assertEquals(null, opoifs.getRoot().getNFileSystem()); stream = root.createDocumentInputStream(top);
assertNotEquals(-1, stream.read());
// Check inside
for(DirectoryNode root : new DirectoryNode[] { opoifs.getRoot(), npoifs.getRoot() }) { // One Level Down
// Top Level DirectoryNode escher = (DirectoryNode) root.getEntry("Escher");
Entry top = root.getEntry("Contents"); Entry one = escher.getEntry("EscherStm");
assertEquals(true, top.isDocumentEntry()); assertTrue(one.isDocumentEntry());
stream = root.createDocumentInputStream(top); stream = escher.createDocumentInputStream(one);
stream.read(); assertNotEquals(-1, stream.read());
// One Level Down // Two Levels Down
DirectoryNode escher = (DirectoryNode)root.getEntry("Escher"); DirectoryNode quill = (DirectoryNode) root.getEntry("Quill");
Entry one = escher.getEntry("EscherStm"); DirectoryNode quillSub = (DirectoryNode) quill.getEntry("QuillSub");
assertEquals(true, one.isDocumentEntry()); Entry two = quillSub.getEntry("CONTENTS");
stream = escher.createDocumentInputStream(one); assertTrue(two.isDocumentEntry());
stream.read(); stream = quillSub.createDocumentInputStream(two);
assertNotEquals(-1, stream.read());
// Two Levels Down }
DirectoryNode quill = (DirectoryNode)root.getEntry("Quill");
DirectoryNode quillSub = (DirectoryNode)quill.getEntry("QuillSub");
Entry two = quillSub.getEntry("CONTENTS");
assertEquals(true, two.isDocumentEntry());
stream = quillSub.createDocumentInputStream(two);
stream.read();
}
} finally {
npoifs.close();
}
} }
@SuppressForbidden("just for testing") @SuppressForbidden("just for testing")

View File

@ -1,73 +0,0 @@
/* ====================================================================
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.poifs.filesystem;
import java.io.*;
import junit.framework.*;
import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.DocumentProperty;
import org.apache.poi.poifs.storage.RawDataBlock;
/**
* Class to test DocumentNode functionality
*
* @author Marc Johnson
*/
public final class TestDocumentNode extends TestCase {
/**
* test constructor
*/
public void testConstructor() throws IOException {
DirectoryProperty property1 = new DirectoryProperty("directory");
RawDataBlock[] rawBlocks = new RawDataBlock[ 4 ];
ByteArrayInputStream stream =
new ByteArrayInputStream(new byte[ 2048 ]);
for (int j = 0; j < 4; j++)
{
rawBlocks[ j ] = new RawDataBlock(stream);
}
OPOIFSDocument document = new OPOIFSDocument("document", rawBlocks,
2000);
DocumentProperty property2 = document.getDocumentProperty();
DirectoryNode parent = new DirectoryNode(property1, (POIFSFileSystem)null, null);
DocumentNode node = new DocumentNode(property2, parent);
// verify we can retrieve the document
assertEquals(property2.getDocument(), node.getDocument());
// verify we can get the size
assertEquals(property2.getSize(), node.getSize());
// verify isDocumentEntry returns true
assertTrue(node.isDocumentEntry());
// verify isDirectoryEntry returns false
assertTrue(!node.isDirectoryEntry());
// verify getName behaves correctly
assertEquals(property2.getName(), node.getName());
// verify getParent behaves correctly
assertEquals(parent, node.getParent());
}
}

View File

@ -17,6 +17,9 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.InputStream; import java.io.InputStream;
@ -26,20 +29,21 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.junit.After;
import org.junit.Test;
/** /**
* Tests bugs across both POIFSFileSystem and NPOIFSFileSystem * Tests bugs across both POIFSFileSystem and NPOIFSFileSystem
*/ */
public final class TestFileSystemBugs extends TestCase { public final class TestFileSystemBugs {
protected static POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); private static POIDataSamples _samples = POIDataSamples.getPOIFSInstance();
protected static POIDataSamples _ssSamples = POIDataSamples.getSpreadSheetInstance(); private static POIDataSamples _ssSamples = POIDataSamples.getSpreadSheetInstance();
protected List<NPOIFSFileSystem> openedFSs; private List<NPOIFSFileSystem> openedFSs;
@Override
protected void tearDown() throws Exception { @After
public void tearDown() {
if (openedFSs != null && !openedFSs.isEmpty()) { if (openedFSs != null && !openedFSs.isEmpty()) {
for (NPOIFSFileSystem fs : openedFSs) { for (NPOIFSFileSystem fs : openedFSs) {
try { try {
@ -51,65 +55,60 @@ public final class TestFileSystemBugs extends TestCase {
} }
openedFSs = null; openedFSs = null;
} }
protected DirectoryNode[] openSample(String name, boolean oldFails) throws Exception {
return openSamples(new InputStream[] {
_samples.openResourceAsStream(name),
_samples.openResourceAsStream(name)
}, oldFails);
}
protected DirectoryNode[] openSSSample(String name, boolean oldFails) throws Exception {
return openSamples(new InputStream[] {
_ssSamples.openResourceAsStream(name),
_ssSamples.openResourceAsStream(name)
}, oldFails);
}
protected DirectoryNode[] openSamples(InputStream[] inps, boolean oldFails) throws Exception {
NPOIFSFileSystem nfs = new NPOIFSFileSystem(inps[0]);
if (openedFSs == null) openedFSs = new ArrayList<>();
openedFSs.add(nfs);
OPOIFSFileSystem ofs = null;
try {
ofs = new OPOIFSFileSystem(inps[1]);
if (oldFails) fail("POIFSFileSystem should have failed but didn't");
} catch (Exception e) {
if (!oldFails) throw e;
}
if (ofs == null) return new DirectoryNode[] { nfs.getRoot() }; private DirectoryNode openSample(String name) throws Exception {
return new DirectoryNode[] { ofs.getRoot(), nfs.getRoot() }; try (InputStream inps = _samples.openResourceAsStream(name)) {
return openSample(inps);
}
}
@SuppressWarnings("SameParameterValue")
private DirectoryNode openSSSample(String name) throws Exception {
try (InputStream inps = _ssSamples.openResourceAsStream(name)) {
return openSample(inps);
}
}
private DirectoryNode openSample(InputStream inps) throws Exception {
NPOIFSFileSystem nfs = new NPOIFSFileSystem(inps);
if (openedFSs == null) {
openedFSs = new ArrayList<>();
}
openedFSs.add(nfs);
return nfs.getRoot();
} }
/** /**
* Test that we can open files that come via Lotus notes. * Test that we can open files that come via Lotus notes.
* These have a top level directory without a name.... * These have a top level directory without a name....
*/ */
@Test
public void testNotesOLE2Files() throws Exception { public void testNotesOLE2Files() throws Exception {
// Check the contents // Check the contents
for (DirectoryNode root : openSample("Notes.ole2", false)) { DirectoryNode root = openSample("Notes.ole2");
assertEquals(1, root.getEntryCount()); assertEquals(1, root.getEntryCount());
Entry entry = root.getEntries().next(); Entry entry = root.getEntries().next();
assertTrue(entry.isDirectoryEntry()); assertTrue(entry.isDirectoryEntry());
assertTrue(entry instanceof DirectoryEntry); assertTrue(entry instanceof DirectoryEntry);
// The directory lacks a name! // The directory lacks a name!
DirectoryEntry dir = (DirectoryEntry)entry; DirectoryEntry dir = (DirectoryEntry)entry;
assertEquals("", dir.getName()); assertEquals("", dir.getName());
// Has two children // Has two children
assertEquals(2, dir.getEntryCount()); assertEquals(2, dir.getEntryCount());
// Check them // Check them
Iterator<Entry> it = dir.getEntries(); Iterator<Entry> it = dir.getEntries();
entry = it.next(); entry = it.next();
assertEquals(true, entry.isDocumentEntry()); assertTrue(entry.isDocumentEntry());
assertEquals(Ole10Native.OLE10_NATIVE, entry.getName()); assertEquals(Ole10Native.OLE10_NATIVE, entry.getName());
entry = it.next(); entry = it.next();
assertEquals(true, entry.isDocumentEntry()); assertTrue(entry.isDocumentEntry());
assertEquals("\u0001CompObj", entry.getName()); assertEquals("\u0001CompObj", entry.getName());
}
} }
/** /**
@ -119,46 +118,39 @@ public final class TestFileSystemBugs extends TestCase {
* Note - only works for NPOIFSFileSystem, POIFSFileSystem * Note - only works for NPOIFSFileSystem, POIFSFileSystem
* can't cope with this level of corruption * can't cope with this level of corruption
*/ */
@Test
public void testCorruptedProperties() throws Exception { public void testCorruptedProperties() throws Exception {
for (DirectoryNode root : openSample("unknown_properties.msg", true)) { DirectoryNode root = openSample("unknown_properties.msg");
assertEquals(42, root.getEntryCount()); assertEquals(42, root.getEntryCount());
}
} }
/** /**
* With heavily nested documents, ensure we still re-write the same * With heavily nested documents, ensure we still re-write the same
*/ */
@Test
public void testHeavilyNestedReWrite() throws Exception { public void testHeavilyNestedReWrite() throws Exception {
for (DirectoryNode root : openSSSample("ex42570-20305.xls", false)) { DirectoryNode root = openSSSample("ex42570-20305.xls");
// Record the structure // Record the structure
Map<String,Integer> entries = new HashMap<>(); Map<String,Integer> entries = new HashMap<>();
fetchSizes("/", root, entries); fetchSizes("/", root, entries);
// Prepare to copy // Prepare to copy
DirectoryNode dest; DirectoryNode dest = new NPOIFSFileSystem().getRoot();
if (root.getNFileSystem() != null) {
dest = (new NPOIFSFileSystem()).getRoot(); // Copy over
} else { EntryUtils.copyNodes(root, dest);
dest = (new OPOIFSFileSystem()).getRoot();
} // Re-load, always as NPOIFS
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Copy over root.getNFileSystem().writeFilesystem(baos);
EntryUtils.copyNodes(root, dest);
NPOIFSFileSystem read = new NPOIFSFileSystem(
// Re-load, always as NPOIFS new ByteArrayInputStream(baos.toByteArray()));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (root.getNFileSystem() != null) { // Check the structure matches
root.getNFileSystem().writeFilesystem(baos); checkSizes("/", read.getRoot(), entries);
} else {
root.getOFileSystem().writeFilesystem(baos);
}
NPOIFSFileSystem read = new NPOIFSFileSystem(
new ByteArrayInputStream(baos.toByteArray()));
// Check the structure matches
checkSizes("/", read.getRoot(), entries);
}
} }
private void fetchSizes(String path, DirectoryNode dir, Map<String,Integer> entries) { private void fetchSizes(String path, DirectoryNode dir, Map<String,Integer> entries) {
for (Entry entry : dir) { for (Entry entry : dir) {
if (entry instanceof DirectoryNode) { if (entry instanceof DirectoryNode) {

View File

@ -17,6 +17,26 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Iterator;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySet;
@ -34,14 +54,6 @@ import org.junit.Assume;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.Iterator;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
/** /**
* Tests for the new NIO POIFSFileSystem implementation * Tests for the new NIO POIFSFileSystem implementation
*/ */
@ -52,7 +64,7 @@ public final class TestNPOIFSFileSystem {
* Returns test files with 512 byte and 4k block sizes, loaded * Returns test files with 512 byte and 4k block sizes, loaded
* both from InputStreams and Files * both from InputStreams and Files
*/ */
protected NPOIFSFileSystem[] get512and4kFileAndInput() throws IOException { private NPOIFSFileSystem[] get512and4kFileAndInput() throws IOException {
NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
NPOIFSFileSystem fsC = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); NPOIFSFileSystem fsC = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
@ -60,7 +72,7 @@ public final class TestNPOIFSFileSystem {
return new NPOIFSFileSystem[] {fsA,fsB,fsC,fsD}; return new NPOIFSFileSystem[] {fsA,fsB,fsC,fsD};
} }
protected static void assertBATCount(NPOIFSFileSystem fs, int expectedBAT, int expectedXBAT) throws IOException { private static void assertBATCount(NPOIFSFileSystem fs, int expectedBAT, int expectedXBAT) throws IOException {
int foundBAT = 0; int foundBAT = 0;
int foundXBAT = 0; int foundXBAT = 0;
int sz = (int)(fs.size() / fs.getBigBlockSize()); int sz = (int)(fs.size() / fs.getBigBlockSize());
@ -75,7 +87,7 @@ public final class TestNPOIFSFileSystem {
assertEquals("Wrong number of BATs", expectedBAT, foundBAT); assertEquals("Wrong number of BATs", expectedBAT, foundBAT);
assertEquals("Wrong number of XBATs with " + expectedBAT + " BATs", expectedXBAT, foundXBAT); assertEquals("Wrong number of XBATs with " + expectedBAT + " BATs", expectedXBAT, foundXBAT);
} }
protected void assertContentsMatches(byte[] expected, DocumentEntry doc) throws IOException { private void assertContentsMatches(byte[] expected, DocumentEntry doc) throws IOException {
NDocumentInputStream inp = new NDocumentInputStream(doc); NDocumentInputStream inp = new NDocumentInputStream(doc);
byte[] contents = new byte[doc.getSize()]; byte[] contents = new byte[doc.getSize()];
assertEquals(doc.getSize(), inp.read(contents)); assertEquals(doc.getSize(), inp.read(contents));
@ -85,21 +97,21 @@ public final class TestNPOIFSFileSystem {
assertThat(expected, equalTo(contents)); assertThat(expected, equalTo(contents));
} }
} }
protected static HeaderBlock writeOutAndReadHeader(NPOIFSFileSystem fs) throws IOException { private static HeaderBlock writeOutAndReadHeader(NPOIFSFileSystem fs) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
fs.writeFilesystem(baos); fs.writeFilesystem(baos);
return new HeaderBlock(new ByteArrayInputStream(baos.toByteArray())); return new HeaderBlock(new ByteArrayInputStream(baos.toByteArray()));
} }
protected static NPOIFSFileSystem writeOutAndReadBack(NPOIFSFileSystem original) throws IOException { static NPOIFSFileSystem writeOutAndReadBack(NPOIFSFileSystem original) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
original.writeFilesystem(baos); original.writeFilesystem(baos);
return new NPOIFSFileSystem(new ByteArrayInputStream(baos.toByteArray())); return new NPOIFSFileSystem(new ByteArrayInputStream(baos.toByteArray()));
} }
protected static NPOIFSFileSystem writeOutFileAndReadBack(NPOIFSFileSystem original) throws IOException { private static NPOIFSFileSystem writeOutFileAndReadBack(NPOIFSFileSystem original) throws IOException {
final File file = TempFile.createTempFile("TestPOIFS", ".ole2"); final File file = TempFile.createTempFile("TestPOIFS", ".ole2");
try (OutputStream fout = new FileOutputStream(file)) { try (OutputStream fout = new FileOutputStream(file)) {
original.writeFilesystem(fout); original.writeFilesystem(fout);
@ -179,7 +191,7 @@ public final class TestNPOIFSFileSystem {
assertEquals("Image", prop.getName()); assertEquals("Image", prop.getName());
prop = pi.next(); prop = pi.next();
assertEquals("Tags", prop.getName()); assertEquals("Tags", prop.getName());
assertEquals(false, pi.hasNext()); assertFalse(pi.hasNext());
// Check the SBAT (Small Blocks FAT) was properly processed // Check the SBAT (Small Blocks FAT) was properly processed
@ -250,7 +262,7 @@ public final class TestNPOIFSFileSystem {
assertEquals("Image", prop.getName()); assertEquals("Image", prop.getName());
prop = pi.next(); prop = pi.next();
assertEquals("Tags", prop.getName()); assertEquals("Tags", prop.getName());
assertEquals(false, pi.hasNext()); assertFalse(pi.hasNext());
// Check the SBAT (Small Blocks FAT) was properly processed // Check the SBAT (Small Blocks FAT) was properly processed
@ -422,7 +434,7 @@ public final class TestNPOIFSFileSystem {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// Our first BAT block has spares // Our first BAT block has spares
assertEquals(true, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertTrue(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
// First free one is 100 // First free one is 100
assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100)); assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100));
@ -463,7 +475,7 @@ public final class TestNPOIFSFileSystem {
} }
// Check our BAT knows it's free // Check our BAT knows it's free
assertEquals(true, fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertTrue(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
// Allocate all the spare ones // Allocate all the spare ones
for(int i=100; i<128; i++) { for(int i=100; i<128; i++) {
@ -471,9 +483,9 @@ public final class TestNPOIFSFileSystem {
} }
// BAT is now full, but there's only the one // BAT is now full, but there's only the one
assertEquals(false, fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
try { try {
assertEquals(false, fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
fail("Should only be one BAT"); fail("Should only be one BAT");
} catch(IndexOutOfBoundsException e) { } catch(IndexOutOfBoundsException e) {
// expected here // expected here
@ -483,9 +495,9 @@ public final class TestNPOIFSFileSystem {
// Now ask for a free one, will need to extend the file // Now ask for a free one, will need to extend the file
assertEquals(129, fs1.getFreeBlock()); assertEquals(129, fs1.getFreeBlock());
assertEquals(false, fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors());
assertEquals(true, fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); assertTrue(fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors());
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(128)); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(128));
assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(129)); assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(129));
@ -502,10 +514,10 @@ public final class TestNPOIFSFileSystem {
fs1.setNextBlock(free, POIFSConstants.END_OF_CHAIN); fs1.setNextBlock(free, POIFSConstants.END_OF_CHAIN);
} }
} }
assertEquals(false, fs1.getBATBlockAndIndex(109*128-1).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors());
try { try {
assertEquals(false, fs1.getBATBlockAndIndex(109*128).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(109 * 128).getBlock().hasFreeSectors());
fail("Should only be 109 BATs"); fail("Should only be 109 BATs");
} catch(IndexOutOfBoundsException e) { } catch(IndexOutOfBoundsException e) {
// expected here // expected here
@ -525,10 +537,10 @@ public final class TestNPOIFSFileSystem {
free = fs1.getFreeBlock(); free = fs1.getFreeBlock();
assertTrue("Had: " + free, free > 0); assertTrue("Had: " + free, free > 0);
assertEquals(false, fs1.getBATBlockAndIndex(109*128-1).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors());
assertEquals(true, fs1.getBATBlockAndIndex(110*128-1).getBlock().hasFreeSectors()); assertTrue(fs1.getBATBlockAndIndex(110 * 128 - 1).getBlock().hasFreeSectors());
try { try {
assertEquals(false, fs1.getBATBlockAndIndex(110*128).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(110 * 128).getBlock().hasFreeSectors());
fail("Should only be 110 BATs"); fail("Should only be 110 BATs");
} catch(IndexOutOfBoundsException e) { } catch(IndexOutOfBoundsException e) {
// expected here // expected here
@ -552,9 +564,9 @@ public final class TestNPOIFSFileSystem {
} }
// Should now have 109+127 = 236 BATs // Should now have 109+127 = 236 BATs
assertEquals(false, fs1.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors());
try { try {
assertEquals(false, fs1.getBATBlockAndIndex(236*128).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(236 * 128).getBlock().hasFreeSectors());
fail("Should only be 236 BATs"); fail("Should only be 236 BATs");
} catch(IndexOutOfBoundsException e) { } catch(IndexOutOfBoundsException e) {
// expected here // expected here
@ -566,10 +578,10 @@ public final class TestNPOIFSFileSystem {
free = fs1.getFreeBlock(); free = fs1.getFreeBlock();
assertTrue("Had: " + free, free > 0); assertTrue("Had: " + free, free > 0);
assertEquals(false, fs1.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors());
assertEquals(true, fs1.getBATBlockAndIndex(237*128-1).getBlock().hasFreeSectors()); assertTrue(fs1.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors());
try { try {
assertEquals(false, fs1.getBATBlockAndIndex(237*128).getBlock().hasFreeSectors()); assertFalse(fs1.getBATBlockAndIndex(237 * 128).getBlock().hasFreeSectors());
fail("Should only be 237 BATs"); fail("Should only be 237 BATs");
} catch(IndexOutOfBoundsException e) { } catch(IndexOutOfBoundsException e) {
// expected here // expected here
@ -590,10 +602,10 @@ public final class TestNPOIFSFileSystem {
// Check that it is seen correctly // Check that it is seen correctly
assertBATCount(fs2, 237, 2); assertBATCount(fs2, 237, 2);
assertEquals(false, fs2.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors()); assertFalse(fs2.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors());
assertEquals(true, fs2.getBATBlockAndIndex(237*128-1).getBlock().hasFreeSectors()); assertTrue(fs2.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors());
try { try {
assertEquals(false, fs2.getBATBlockAndIndex(237*128).getBlock().hasFreeSectors()); assertFalse(fs2.getBATBlockAndIndex(237 * 128).getBlock().hasFreeSectors());
fail("Should only be 237 BATs"); fail("Should only be 237 BATs");
} catch(IndexOutOfBoundsException e) { } catch(IndexOutOfBoundsException e) {
// expected here // expected here
@ -620,12 +632,12 @@ public final class TestNPOIFSFileSystem {
Entry si = root.getEntry("\u0005SummaryInformation"); Entry si = root.getEntry("\u0005SummaryInformation");
Entry image = root.getEntry("Image"); Entry image = root.getEntry("Image");
Entry tags = root.getEntry("Tags"); Entry tags = root.getEntry("Tags");
assertEquals(false, thumbnail.isDirectoryEntry()); assertFalse(thumbnail.isDirectoryEntry());
assertEquals(false, dsi.isDirectoryEntry()); assertFalse(dsi.isDirectoryEntry());
assertEquals(false, si.isDirectoryEntry()); assertFalse(si.isDirectoryEntry());
assertEquals(true, image.isDirectoryEntry()); assertTrue(image.isDirectoryEntry());
assertEquals(false, tags.isDirectoryEntry()); assertFalse(tags.isDirectoryEntry());
// Check via the iterator // Check via the iterator
Iterator<Entry> it = root.getEntries(); Iterator<Entry> it = root.getEntries();
@ -652,8 +664,8 @@ public final class TestNPOIFSFileSystem {
for(NPOIFSFileSystem fs : get512and4kFileAndInput()) { for(NPOIFSFileSystem fs : get512and4kFileAndInput()) {
DirectoryEntry root = fs.getRoot(); DirectoryEntry root = fs.getRoot();
Entry si = root.getEntry("\u0005SummaryInformation"); Entry si = root.getEntry("\u0005SummaryInformation");
assertEquals(true, si.isDocumentEntry()); assertTrue(si.isDocumentEntry());
DocumentNode doc = (DocumentNode)si; DocumentNode doc = (DocumentNode)si;
// Check we can read it // Check we can read it
@ -665,9 +677,9 @@ public final class TestNPOIFSFileSystem {
SummaryInformation inf = (SummaryInformation)ps; SummaryInformation inf = (SummaryInformation)ps;
// Check some bits in it // Check some bits in it
assertEquals(null, inf.getApplicationName()); assertNull(inf.getApplicationName());
assertEquals(null, inf.getAuthor()); assertNull(inf.getAuthor());
assertEquals(null, inf.getSubject()); assertNull(inf.getSubject());
assertEquals(131333, inf.getOSVersion()); assertEquals(131333, inf.getOSVersion());
// Finish with this one // Finish with this one
@ -676,7 +688,7 @@ public final class TestNPOIFSFileSystem {
// Try the other summary information // Try the other summary information
si = root.getEntry("\u0005DocumentSummaryInformation"); si = root.getEntry("\u0005DocumentSummaryInformation");
assertEquals(true, si.isDocumentEntry()); assertTrue(si.isDocumentEntry());
doc = (DocumentNode)si; doc = (DocumentNode)si;
assertContentsMatches(null, doc); assertContentsMatches(null, doc);
@ -1541,7 +1553,7 @@ public final class TestNPOIFSFileSystem {
DirectoryEntry vbaProj = (DirectoryEntry)src.getRoot().getEntry("_VBA_PROJECT_CUR"); DirectoryEntry vbaProj = (DirectoryEntry)src.getRoot().getEntry("_VBA_PROJECT_CUR");
assertEquals(3, vbaProj.getEntryCount()); assertEquals(3, vbaProj.getEntryCount());
// Can't delete yet, has stuff // Can't delete yet, has stuff
assertEquals(false, vbaProj.delete()); assertFalse(vbaProj.delete());
// Recursively delete // Recursively delete
_recursiveDeletee(vbaProj); _recursiveDeletee(vbaProj);
@ -1554,7 +1566,7 @@ public final class TestNPOIFSFileSystem {
} }
private void _recursiveDeletee(Entry entry) throws IOException { private void _recursiveDeletee(Entry entry) throws IOException {
if (entry.isDocumentEntry()) { if (entry.isDocumentEntry()) {
assertEquals(true, entry.delete()); assertTrue(entry.delete());
return; return;
} }
@ -1564,7 +1576,7 @@ public final class TestNPOIFSFileSystem {
Entry ce = dir.getEntry(name); Entry ce = dir.getEntry(name);
_recursiveDeletee(ce); _recursiveDeletee(ce);
} }
assertEquals(true, dir.delete()); assertTrue(dir.delete());
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private int _countChildren(DirectoryProperty p) { private int _countChildren(DirectoryProperty p) {
@ -1677,24 +1689,24 @@ public final class TestNPOIFSFileSystem {
fs.createDocument(new DummyDataInputStream(s2gb), "Big"); fs.createDocument(new DummyDataInputStream(s2gb), "Big");
} }
protected static class DummyDataInputStream extends InputStream { private static final class DummyDataInputStream extends InputStream {
protected final long maxSize; private final long maxSize;
protected long size; private long size;
public DummyDataInputStream(long maxSize) { private DummyDataInputStream(long maxSize) {
this.maxSize = maxSize; this.maxSize = maxSize;
this.size = 0; this.size = 0;
} }
public int read() throws IOException { public int read() {
if (size >= maxSize) return -1; if (size >= maxSize) return -1;
size++; size++;
return (int)(size % 128); return (int)(size % 128);
} }
public int read(byte[] b) throws IOException { public int read(byte[] b) {
return read(b, 0, b.length); return read(b, 0, b.length);
} }
public int read(byte[] b, int offset, int len) throws IOException { public int read(byte[] b, int offset, int len) {
if (size >= maxSize) return -1; if (size >= maxSize) return -1;
int sz = (int)Math.min(len, maxSize-size); int sz = (int)Math.min(len, maxSize-size);
for (int i=0; i<sz; i++) { for (int i=0; i<sz; i++) {
@ -1715,8 +1727,8 @@ public final class TestNPOIFSFileSystem {
for (int i = 0; i < iterations; i++) { for (int i = 0; i < iterations; i++) {
try (InputStream inputStream = POIDataSamples.getHSMFInstance().openResourceAsStream("lots-of-recipients.msg")) { try (InputStream inputStream = POIDataSamples.getHSMFInstance().openResourceAsStream("lots-of-recipients.msg")) {
OPOIFSFileSystem srcFileSystem = new OPOIFSFileSystem(inputStream); NPOIFSFileSystem srcFileSystem = new NPOIFSFileSystem(inputStream);
OPOIFSFileSystem destFileSystem = new OPOIFSFileSystem(); NPOIFSFileSystem destFileSystem = new NPOIFSFileSystem();
copyAllEntries(srcFileSystem.getRoot(), destFileSystem.getRoot()); copyAllEntries(srcFileSystem.getRoot(), destFileSystem.getRoot());
@ -1727,7 +1739,6 @@ public final class TestNPOIFSFileSystem {
assertTrue(file.delete()); assertTrue(file.delete());
if (i % 10 == 0) System.out.print("."); if (i % 10 == 0) System.out.print(".");
if (i % 800 == 0 && i > 0) System.out.println();
} }
} }
@ -1754,7 +1765,6 @@ public final class TestNPOIFSFileSystem {
assertTrue(file.delete()); assertTrue(file.delete());
if (i % 10 == 0) System.out.print("."); if (i % 10 == 0) System.out.print(".");
if (i % 800 == 0 && i > 0) System.out.println();
} }
} }

View File

@ -17,14 +17,16 @@
package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSBigBlockSize;
@ -34,18 +36,21 @@ import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.HeaderBlock; import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.RawDataBlockList; import org.apache.poi.poifs.storage.RawDataBlockList;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/** /**
* Tests for the older OPOIFS-based POIFSFileSystem * Tests for the older OPOIFS-based POIFSFileSystem
*/ */
public final class TestPOIFSFileSystem extends TestCase { public final class TestPOIFSFileSystem {
private final POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); private final POIDataSamples _samples = POIDataSamples.getPOIFSInstance();
/** /**
* Mock exception used to ensure correct error handling * Mock exception used to ensure correct error handling
*/ */
private static final class MyEx extends RuntimeException { private static final class MyEx extends RuntimeException {
public MyEx() { MyEx() {
// no fields to initialise // no fields to initialise
} }
} }
@ -60,7 +65,7 @@ public final class TestPOIFSFileSystem extends TestCase {
private int _currentIx; private int _currentIx;
private boolean _isClosed; private boolean _isClosed;
public TestIS(InputStream is, int failIndex) { TestIS(InputStream is, int failIndex) {
_is = is; _is = is;
_failIndex = failIndex; _failIndex = failIndex;
_currentIx = 0; _currentIx = 0;
@ -93,7 +98,7 @@ public final class TestPOIFSFileSystem extends TestCase {
_isClosed = true; _isClosed = true;
_is.close(); _is.close();
} }
public boolean isClosed() { boolean isClosed() {
return _isClosed; return _isClosed;
} }
} }
@ -102,29 +107,26 @@ public final class TestPOIFSFileSystem extends TestCase {
* Test for undesired behaviour observable as of svn revision 618865 (5-Feb-2008). * Test for undesired behaviour observable as of svn revision 618865 (5-Feb-2008).
* POIFSFileSystem was not closing the input stream. * POIFSFileSystem was not closing the input stream.
*/ */
public void testAlwaysClose() { @Test
public void testAlwaysClose() throws IOException {
TestIS testIS; TestIS testIS;
// Normal case - read until EOF and close // Normal case - read until EOF and close
testIS = new TestIS(openSampleStream("13224.xls"), -1); testIS = new TestIS(openSampleStream("13224.xls"), -1);
try { try (NPOIFSFileSystem ignored = new NPOIFSFileSystem(testIS)){
new OPOIFSFileSystem(testIS); assertTrue("input stream was not closed", testIS.isClosed());
} catch (IOException e) {
throw new RuntimeException(e);
} }
assertTrue("input stream was not closed", testIS.isClosed());
// intended to crash after reading 10000 bytes // intended to crash after reading 10000 bytes
testIS = new TestIS(openSampleStream("13224.xls"), 10000); testIS = new TestIS(openSampleStream("13224.xls"), 10000);
try { try (NPOIFSFileSystem ignored = new NPOIFSFileSystem(testIS)){
new OPOIFSFileSystem(testIS);
fail("ex should have been thrown"); fail("ex should have been thrown");
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyEx e) { } catch (MyEx e) {
// expected // expected
assertTrue("input stream was not closed", testIS.isClosed()); // but still should close
} catch (Exception e) {
fail("MyEx is expected to be thrown");
} }
assertTrue("input stream was not closed", testIS.isClosed()); // but still should close
} }
/** /**
@ -138,6 +140,7 @@ public final class TestPOIFSFileSystem extends TestCase {
* The other is to fix the handling of the last block in * The other is to fix the handling of the last block in
* POIFS, since it seems to be slight wrong * POIFS, since it seems to be slight wrong
*/ */
@Test
public void testShortLastBlock() throws Exception { public void testShortLastBlock() throws Exception {
String[] files = new String[] { String[] files = new String[] {
"ShortLastBlock.qwp", "ShortLastBlock.wps" "ShortLastBlock.qwp", "ShortLastBlock.wps"
@ -145,7 +148,7 @@ public final class TestPOIFSFileSystem extends TestCase {
for (String file : files) { for (String file : files) {
// Open the file up // Open the file up
OPOIFSFileSystem fs = new OPOIFSFileSystem( NPOIFSFileSystem fs = new NPOIFSFileSystem(
_samples.openResourceAsStream(file) _samples.openResourceAsStream(file)
); );
@ -156,26 +159,24 @@ public final class TestPOIFSFileSystem extends TestCase {
// Check sizes // Check sizes
} }
} }
@Rule
public ExpectedException expectedEx = ExpectedException.none();
/** /**
* Check that we do the right thing when the list of which * Check that we do the right thing when the list of which
* sectors are BAT blocks points off the list of * sectors are BAT blocks points off the list of
* sectors that exist in the file. * sectors that exist in the file.
*/ */
@Test
public void testFATandDIFATsectors() throws Exception { public void testFATandDIFATsectors() throws Exception {
// Open the file up // Open the file up
try { expectedEx.expect(IndexOutOfBoundsException.class);
InputStream stream = _samples.openResourceAsStream("ReferencesInvalidSectors.mpp"); expectedEx.expectMessage("Block 1148 not found");
try { try (InputStream stream = _samples.openResourceAsStream("ReferencesInvalidSectors.mpp")) {
new OPOIFSFileSystem(stream); new NPOIFSFileSystem(stream);
fail("File is corrupt and shouldn't have been opened"); fail("File is corrupt and shouldn't have been opened");
} finally { }
stream.close();
}
} catch (IOException e) {
String msg = e.getMessage();
assertTrue(msg.startsWith("Your file contains 695 sectors"));
}
} }
/** /**
@ -184,9 +185,10 @@ public final class TestPOIFSFileSystem extends TestCase {
* However, because a file needs to be at least 6.875mb big * However, because a file needs to be at least 6.875mb big
* to have an XBAT in it, we don't have a test one. So, generate it. * to have an XBAT in it, we don't have a test one. So, generate it.
*/ */
@Test
public void testBATandXBAT() throws Exception { public void testBATandXBAT() throws Exception {
byte[] hugeStream = new byte[8*1024*1024]; byte[] hugeStream = new byte[8*1024*1024];
OPOIFSFileSystem fs = new OPOIFSFileSystem(); NPOIFSFileSystem fs = new NPOIFSFileSystem();
fs.getRoot().createDocument( fs.getRoot().createDocument(
"BIG", new ByteArrayInputStream(hugeStream) "BIG", new ByteArrayInputStream(hugeStream)
); );
@ -229,8 +231,7 @@ public final class TestPOIFSFileSystem extends TestCase {
assertEquals(fsData.length / 512, blockList.blockCount() + 1); // Header not counted assertEquals(fsData.length / 512, blockList.blockCount() + 1); // Header not counted
// Now load it and check // Now load it and check
fs = null; fs = new NPOIFSFileSystem(
fs = new OPOIFSFileSystem(
new ByteArrayInputStream(fsData) new ByteArrayInputStream(fsData)
); );
@ -244,41 +245,39 @@ public final class TestPOIFSFileSystem extends TestCase {
* Most OLE2 files use 512byte blocks. However, a small number * Most OLE2 files use 512byte blocks. However, a small number
* use 4k blocks. Check that we can open these. * use 4k blocks. Check that we can open these.
*/ */
@Test
public void test4KBlocks() throws Exception { public void test4KBlocks() throws Exception {
POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); POIDataSamples _samples = POIDataSamples.getPOIFSInstance();
InputStream inp = _samples.openResourceAsStream("BlockSize4096.zvi"); try (InputStream inp = _samples.openResourceAsStream("BlockSize4096.zvi")) {
try { // First up, check that we can process the header properly
// First up, check that we can process the header properly HeaderBlock header_block = new HeaderBlock(inp);
HeaderBlock header_block = new HeaderBlock(inp); POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize();
POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize(); assertEquals(4096, bigBlockSize.getBigBlockSize());
assertEquals(4096, bigBlockSize.getBigBlockSize());
// Check the fat info looks sane // Check the fat info looks sane
assertEquals(1, header_block.getBATArray().length); assertEquals(1, header_block.getBATArray().length);
assertEquals(1, header_block.getBATCount()); assertEquals(1, header_block.getBATCount());
assertEquals(0, header_block.getXBATCount()); assertEquals(0, header_block.getXBATCount());
// Now check we can get the basic fat // Now check we can get the basic fat
RawDataBlockList data_blocks = new RawDataBlockList(inp, RawDataBlockList data_blocks = new RawDataBlockList(inp,
bigBlockSize); bigBlockSize);
assertEquals(15, data_blocks.blockCount()); assertEquals(15, data_blocks.blockCount());
// Now try and open properly // Now try and open properly
OPOIFSFileSystem fs = new OPOIFSFileSystem( NPOIFSFileSystem fs = new NPOIFSFileSystem(
_samples.openResourceAsStream("BlockSize4096.zvi")); _samples.openResourceAsStream("BlockSize4096.zvi"));
assertTrue(fs.getRoot().getEntryCount() > 3); assertTrue(fs.getRoot().getEntryCount() > 3);
// Check we can get at all the contents // Check we can get at all the contents
checkAllDirectoryContents(fs.getRoot()); checkAllDirectoryContents(fs.getRoot());
// Finally, check we can do a similar 512byte one too // Finally, check we can do a similar 512byte one too
fs = new OPOIFSFileSystem( fs = new NPOIFSFileSystem(
_samples.openResourceAsStream("BlockSize512.zvi")); _samples.openResourceAsStream("BlockSize512.zvi"));
assertTrue(fs.getRoot().getEntryCount() > 3); assertTrue(fs.getRoot().getEntryCount() > 3);
checkAllDirectoryContents(fs.getRoot()); checkAllDirectoryContents(fs.getRoot());
} finally { }
inp.close();
}
} }
private void checkAllDirectoryContents(DirectoryEntry dir) throws IOException { private void checkAllDirectoryContents(DirectoryEntry dir) throws IOException {
for(Entry entry : dir) { for(Entry entry : dir) {
@ -293,6 +292,7 @@ public final class TestPOIFSFileSystem extends TestCase {
} }
} }
@SuppressWarnings("SameParameterValue")
private static InputStream openSampleStream(String sampleFileName) { private static InputStream openSampleStream(String sampleFileName) {
return HSSFTestDataSamples.openSampleFileStream(sampleFileName); return HSSFTestDataSamples.openSampleFileStream(sampleFileName);
} }

View File

@ -20,7 +20,7 @@ package org.apache.poi.poifs.storage;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
/** /**
* Tests for org.apache.poi.poifs.storage<br> * Tests for org.apache.poi.poifs.storage
*/ */
@RunWith(Suite.class) @RunWith(Suite.class)
@Suite.SuiteClasses({ @Suite.SuiteClasses({
@ -33,11 +33,7 @@ import org.junit.runners.Suite;
TestHeaderBlockWriting.class, TestHeaderBlockWriting.class,
TestPropertyBlock.class, TestPropertyBlock.class,
TestRawDataBlock.class, TestRawDataBlock.class,
TestRawDataBlockList.class, TestRawDataBlockList.class
TestSmallBlockTableReader.class,
TestSmallBlockTableWriter.class,
TestSmallDocumentBlock.class,
TestSmallDocumentBlockList.class
}) })
public class AllPOIFSStorageTests { public class AllPOIFSStorageTests {
} }

View File

@ -17,196 +17,58 @@
package org.apache.poi.poifs.storage; package org.apache.poi.poifs.storage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.HexRead; import org.apache.poi.util.HexRead;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.junit.Test;
/** /**
* Class to test BlockAllocationTableReader functionality * Class to test BlockAllocationTableReader functionality
*
* @author Marc Johnson
*/ */
public final class TestBlockAllocationTableReader extends TestCase { public class TestBlockAllocationTableReader {
/** /**
* Test small block allocation table constructor * Test small block allocation table constructor
*/ */
@Test
public void testSmallBATConstructor() throws IOException { public void testSmallBATConstructor() throws IOException {
// need to create an array of raw blocks containing the SBAT, // need to create an array of raw blocks containing the SBAT,
// and a small document block list // and a small document block list
String[] sbat_data = { final String sbat_data = "H4sIAAAAAAAAAPv/nzjwj4ZYiYGBAZfcKKAtAAC/sexrAAIAAA==";
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF",
"FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF",
"FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF",
"FE FF FF FF 22 00 00 00 FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
};
RawDataBlock[] sbats = { new RawDataBlock(makeDataStream(sbat_data)) }; RawDataBlock[] sbats = { new RawDataBlock(new ByteArrayInputStream(RawDataUtil.decompress(sbat_data))) };
String[] sbt_data = { final String sbt_data =
"08 00 28 00 6A 61 6D 65 73 2D 55 37 37 32 37 39 32 2D 28 31 36 2D 4F 63 74 2D 32 30 30 31 40 31", "H4sIAAAAAAAAAONg0GDISsxNLdYNNTc3Mrc00tUwNNP1Ty7RNTIwMHQAsk0MdY2NNfWiXNwYsAB2MNmg/sgBmyxhQB395AMm" +
"36 2D 34 31 2D 33 33 29 2E 5A 44 46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "BkaK9HNQaD83hfqZKXY/E4OCIQcDK0NwYllqCgeDOEOwnkdocLCjp5+Co4KLa5iCv5tbkEKoNwfQrUhJA6TFVM9Yz4gy94OM" +
"07 00 00 00 00 00 80 27 E2 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "Aac/svVTaj8zg7tTAAX6ZRk0HDWRAkahJF8BiUtQPyMDITX4ABMFegeDfsrjjzLAxCBBoX7KwED7n/LwG2j7KSv/Bt79A2s/" +
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "NdzPQUWaVDDQ/h/o+meop5+hrx9ng4ku9jOhYVIBM4X2j4KhDQAtwD4rAA4AAA==";
"07 00 00 00 00 00 80 27 E2 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"03 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 02 00 20 31 08 00 05 00 53 61 76 65 64 08 00 17 00 53 2E 48 55 53 53 41 49 4E 20 41 20 44",
"45 56 20 4F 46 46 52 20 55 4B 08 00 0B 00 31 36 2D 4F 63 74 2D 32 30 30 31 08 00 05 00 35 2E 33",
"2E 32 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 05 00 6A 61 6D 65 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 03 00 47 42 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 1D 00 28 41 29 31 36 2D 4F 63 74 2D 32 30 30 31 20 74 6F 20 31 36 2D 4F 63 74 2D 32 30 30",
"31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 01 00 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00",
"02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00",
"02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 03 00 47 42 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 17 00 53 2E 48 55 53 53 41 49 4E 20 41 20 44 45 56 20 4F 46 46 52 20 55 4B 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
};
RawDataBlock[] sbts = new RawDataBlock[7]; InputStream sbt_input = new ByteArrayInputStream(RawDataUtil.decompress(sbt_data));
InputStream sbt_input = makeDataStream(sbt_data);
for (int j = 0; j < 7; j++) { BlockListImpl small_blocks = new RawDataBlockList(sbt_input, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
sbts[j] = new RawDataBlock(sbt_input); int blockCount = small_blocks.blockCount();
ListManagedBlock[] lmb = new ListManagedBlock[7*blockCount];
for (int i=0; i<lmb.length; i++) {
lmb[i] = small_blocks.get(i % blockCount);
} }
SmallDocumentBlockList small_blocks = new SmallDocumentBlockList(SmallDocumentBlock small_blocks.setBlocks(lmb);
.extract(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, sbts));
BlockAllocationTableReader sbat = new BlockAllocationTableReader( BlockAllocationTableReader sbat = new BlockAllocationTableReader(
POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, sbats, small_blocks); POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, sbats, small_blocks);
boolean[] isUsed = {
false, false, false, false, false, false, false, false, false,
false, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false
};
int[] nextIndex = { int[] nextIndex = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
@ -219,13 +81,13 @@ public final class TestBlockAllocationTableReader extends TestCase {
}; };
for (int j = 0; j < 128; j++) { for (int j = 0; j < 128; j++) {
if (isUsed[j]) { final boolean isUsed = nextIndex[j] != -1;
assertTrue("checking usage of block " + j, sbat.isUsed(j)); assertEquals("checking usage of block " + j, isUsed, sbat.isUsed(j));
assertEquals("checking usage of block " + j, nextIndex[j], sbat
.getNextBlockIndex(j)); if (isUsed) {
assertEquals("checking usage of block " + j, nextIndex[j], sbat.getNextBlockIndex(j));
small_blocks.remove(j); small_blocks.remove(j);
} else { } else {
assertTrue("checking usage of block " + j, !sbat.isUsed(j));
try { try {
small_blocks.remove(j); small_blocks.remove(j);
fail("removing block " + j + " should have failed"); fail("removing block " + j + " should have failed");
@ -236,10 +98,7 @@ public final class TestBlockAllocationTableReader extends TestCase {
} }
} }
private static InputStream makeDataStream(String[] hexDataLines) { @Test
return new ByteArrayInputStream(RawDataUtil.decode(hexDataLines));
}
public void testReadingConstructor() throws IOException { public void testReadingConstructor() throws IOException {
// create a document, minus the header block, and use that to // create a document, minus the header block, and use that to
@ -288,6 +147,7 @@ public final class TestBlockAllocationTableReader extends TestCase {
} }
} }
@Test
public void testFetchBlocks() throws IOException { public void testFetchBlocks() throws IOException {
// strategy: // strategy:
@ -372,10 +232,8 @@ public final class TestBlockAllocationTableReader extends TestCase {
assertEquals(expected_length[j], dataBlocks.length); assertEquals(expected_length[j], dataBlocks.length);
} }
} catch (IOException e) { } catch (IOException e) {
if (expected_length[j] == -1) { if (expected_length[j] != -1) {
// -1 would be a expected failure here, anything else not
// no problem, we expected a failure here
} else {
throw e; throw e;
} }
} }
@ -386,6 +244,7 @@ public final class TestBlockAllocationTableReader extends TestCase {
* Bugzilla 48085 describes an error where a corrupted Excel file causes POI to throw an * Bugzilla 48085 describes an error where a corrupted Excel file causes POI to throw an
* {@link OutOfMemoryError}. * {@link OutOfMemoryError}.
*/ */
@Test
public void testBadSectorAllocationTableSize_bug48085() { public void testBadSectorAllocationTableSize_bug48085() {
int BLOCK_SIZE = 512; int BLOCK_SIZE = 512;
POIFSBigBlockSize bigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; POIFSBigBlockSize bigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;

View File

@ -1,317 +0,0 @@
/* ====================================================================
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.poifs.storage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import junit.framework.TestCase;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.property.RootProperty;
/**
* Class to test SmallBlockTableReader functionality
*
* @author Marc Johnson
*/
public final class TestSmallBlockTableReader extends TestCase {
public void testReadingConstructor() throws IOException {
// first, we need the raw data blocks
String[] raw_data_array = {
"52 00 6F 00 6F 00 74 00 20 00 45 00 6E 00 74 00 72 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"16 00 05 01 FF FF FF FF FF FF FF FF 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00 80 07 00 00 00 00 00 00",
"44 00 65 00 61 00 6C 00 20 00 49 00 6E 00 66 00 6F 00 72 00 6D 00 61 00 74 00 69 00 6F 00 6E 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"22 00 01 01 FF FF FF FF FF FF FF FF 15 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"46 00 55 00 44 00 20 00 47 00 72 00 69 00 64 00 20 00 49 00 6E 00 66 00 6F 00 72 00 6D 00 61 00",
"74 00 69 00 6F 00 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"2A 00 02 01 FF FF FF FF 0E 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"44 00 6F 00 75 00 62 00 6C 00 65 00 20 00 44 00 65 00 61 00 6C 00 69 00 6E 00 67 00 20 00 49 00",
"6E 00 64 00 69 00 63 00 61 00 74 00 6F 00 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"32 00 02 01 FF FF FF FF 09 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00",
"43 00 68 00 69 00 6C 00 64 00 20 00 50 00 65 00 72 00 63 00 65 00 6E 00 74 00 61 00 67 00 65 00",
"20 00 50 00 65 00 72 00 6D 00 69 00 74 00 74 00 65 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00",
"36 00 02 01 FF FF FF FF 07 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 00 00 00 00 00 00 00",
"43 00 61 00 6E 00 63 00 65 00 6C 00 6C 00 61 00 74 00 69 00 6F 00 6E 00 20 00 46 00 65 00 65 00",
"20 00 46 00 69 00 78 00 65 00 64 00 20 00 56 00 61 00 6C 00 75 00 65 00 00 00 00 00 00 00 00 00",
"3A 00 02 01 FF FF FF FF 06 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 04 00 00 00 00 00 00 00",
"55 00 6D 00 62 00 72 00 65 00 6C 00 6C 00 61 00 20 00 4C 00 69 00 6E 00 6B 00 73 00 20 00 61 00",
"6E 00 64 00 20 00 50 00 61 00 73 00 73 00 65 00 6E 00 67 00 65 00 72 00 73 00 00 00 00 00 00 00",
"3C 00 02 01 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"43 00 61 00 6E 00 63 00 65 00 6C 00 6C 00 61 00 74 00 69 00 6F 00 6E 00 20 00 46 00 65 00 65 00",
"20 00 50 00 65 00 72 00 63 00 65 00 6E 00 74 00 61 00 67 00 65 00 00 00 00 00 00 00 00 00 00 00",
"38 00 02 01 FF FF FF FF 05 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00 00 00 00 00",
"49 00 6E 00 66 00 61 00 6E 00 74 00 20 00 44 00 69 00 73 00 63 00 6F 00 75 00 6E 00 74 00 20 00",
"50 00 65 00 72 00 6D 00 69 00 74 00 74 00 65 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"34 00 02 01 FF FF FF FF 04 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 04 00 00 00 00 00 00 00",
"43 00 61 00 6E 00 63 00 65 00 6C 00 6C 00 61 00 74 00 69 00 6F 00 6E 00 20 00 46 00 65 00 65 00",
"20 00 43 00 75 00 72 00 72 00 65 00 6E 00 63 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"34 00 02 01 FF FF FF FF 08 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 07 00 00 00 00 00 00 00",
"4F 00 75 00 74 00 62 00 6F 00 75 00 6E 00 64 00 20 00 54 00 72 00 61 00 76 00 65 00 6C 00 20 00",
"44 00 61 00 74 00 65 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"2C 00 02 01 FF FF FF FF 0B 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 21 00 00 00 00 00 00 00",
"42 00 75 00 73 00 69 00 6E 00 65 00 73 00 73 00 20 00 4A 00 75 00 73 00 74 00 69 00 66 00 69 00",
"63 00 61 00 74 00 69 00 6F 00 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"2E 00 02 01 FF FF FF FF 03 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 04 00 00 00 00 00 00 00",
"49 00 6E 00 66 00 61 00 6E 00 74 00 20 00 44 00 69 00 73 00 63 00 6F 00 75 00 6E 00 74 00 20 00",
"56 00 61 00 6C 00 75 00 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"2C 00 02 01 FF FF FF FF 0D 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 00 00 00 00 00 00 00",
"4F 00 74 00 68 00 65 00 72 00 20 00 43 00 61 00 72 00 72 00 69 00 65 00 72 00 20 00 53 00 65 00",
"63 00 74 00 6F 00 72 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"2C 00 02 01 FF FF FF FF 0A 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 00 00 00 04 00 00 00 00 00 00 00",
"4E 00 75 00 6D 00 62 00 65 00 72 00 20 00 6F 00 66 00 20 00 50 00 61 00 73 00 73 00 65 00 6E 00",
"67 00 65 00 72 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"2A 00 02 01 FF FF FF FF 0C 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00 04 00 00 00 00 00 00 00",
"53 00 61 00 6C 00 65 00 73 00 20 00 41 00 72 00 65 00 61 00 20 00 43 00 6F 00 64 00 65 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"20 00 02 01 1C 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B 00 00 00 04 00 00 00 00 00 00 00",
"4F 00 74 00 68 00 65 00 72 00 20 00 52 00 65 00 66 00 75 00 6E 00 64 00 20 00 54 00 65 00 78 00",
"74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"24 00 02 01 17 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 00 00 04 00 00 00 00 00 00 00",
"4D 00 61 00 78 00 69 00 6D 00 75 00 6D 00 20 00 53 00 74 00 61 00 79 00 20 00 50 00 65 00 72 00",
"69 00 6F 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"28 00 02 01 FF FF FF FF 14 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0D 00 00 00 04 00 00 00 00 00 00 00",
"4E 00 65 00 74 00 20 00 52 00 65 00 6D 00 69 00 74 00 20 00 50 00 65 00 72 00 6D 00 69 00 74 00",
"74 00 65 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"28 00 02 01 FF FF FF FF 13 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0E 00 00 00 04 00 00 00 00 00 00 00",
"50 00 65 00 72 00 63 00 65 00 6E 00 74 00 61 00 67 00 65 00 20 00 6F 00 66 00 20 00 59 00 69 00",
"65 00 6C 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"28 00 02 01 FF FF FF FF 02 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0F 00 00 00 04 00 00 00 00 00 00 00",
"4E 00 61 00 74 00 75 00 72 00 65 00 20 00 6F 00 66 00 20 00 56 00 61 00 72 00 69 00 61 00 74 00",
"69 00 6F 00 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"28 00 02 01 FF FF FF FF 12 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 50 00 00 00 00 00 00 00",
"46 00 55 00 44 00 20 00 47 00 72 00 69 00 64 00 20 00 44 00 69 00 6D 00 65 00 6E 00 73 00 69 00",
"6F 00 6E 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"28 00 02 01 10 00 00 00 11 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 00 00 00 04 00 00 00 00 00 00 00",
"44 00 65 00 61 00 6C 00 20 00 44 00 65 00 73 00 63 00 72 00 69 00 70 00 74 00 69 00 6F 00 6E 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"22 00 02 01 19 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 00 00 09 00 00 00 00 00 00 00",
"54 00 52 00 56 00 41 00 20 00 49 00 6E 00 66 00 6F 00 72 00 6D 00 61 00 74 00 69 00 6F 00 6E 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"22 00 02 01 18 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 04 00 00 00 00 00 00 00",
"50 00 72 00 6F 00 72 00 61 00 74 00 65 00 20 00 43 00 6F 00 6D 00 6D 00 65 00 6E 00 74 00 73 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"22 00 02 01 16 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"43 00 6F 00 6D 00 6D 00 69 00 73 00 73 00 69 00 6F 00 6E 00 20 00 56 00 61 00 6C 00 75 00 65 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"22 00 02 01 0F 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 15 00 00 00 04 00 00 00 00 00 00 00",
"4D 00 61 00 78 00 69 00 6D 00 75 00 6D 00 20 00 53 00 74 00 61 00 79 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"1A 00 02 01 20 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 05 00 00 00 00 00 00 00",
"44 00 65 00 61 00 6C 00 20 00 43 00 75 00 72 00 72 00 65 00 6E 00 63 00 79 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"1C 00 02 01 1D 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 00 00 00 07 00 00 00 00 00 00 00",
"43 00 6F 00 6E 00 73 00 6F 00 72 00 74 00 69 00 61 00 20 00 43 00 6F 00 64 00 65 00 73 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"20 00 02 01 1B 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"42 00 75 00 73 00 69 00 6E 00 65 00 73 00 73 00 20 00 54 00 79 00 70 00 65 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"1C 00 02 01 1A 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 04 00 00 00 00 00 00 00",
"44 00 65 00 61 00 6C 00 20 00 54 00 79 00 70 00 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"14 00 02 01 23 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 19 00 00 00 04 00 00 00 00 00 00 00",
"53 00 75 00 72 00 63 00 68 00 61 00 72 00 67 00 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"14 00 02 01 21 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1A 00 00 00 04 00 00 00 00 00 00 00",
"41 00 67 00 65 00 6E 00 74 00 73 00 20 00 4E 00 61 00 6D 00 65 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"18 00 02 01 1F 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1B 00 00 00 04 00 00 00 00 00 00 00",
"46 00 61 00 72 00 65 00 20 00 54 00 79 00 70 00 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"14 00 02 01 1E 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1C 00 00 00 04 00 00 00 00 00 00 00",
"53 00 75 00 62 00 20 00 44 00 65 00 61 00 6C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"12 00 02 01 24 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1D 00 00 00 04 00 00 00 00 00 00 00",
"41 00 4C 00 43 00 20 00 43 00 6F 00 64 00 65 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"14 00 02 01 22 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"52 00 65 00 6D 00 61 00 72 00 6B 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"10 00 02 01 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 03 00 47 42 50 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 1D 00 28 41 29 31 36 2D 4F 63 74 2D 32 30 30 31 20 74 6F 20 31 36 2D 4F 63 74 2D 32 30 30",
"31 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 01 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00",
"02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00",
"02 00 00 00 08 00 00 00 02 00 00 00 08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 18 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 05 00 6A 61 6D 65 73 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 01 00 31 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 03 00 47 42 50 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"08 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"02 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF",
"FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF",
"11 00 00 00 FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF",
"FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FE FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00",
"09 00 00 00 FE FF FF FF 0B 00 00 00 0C 00 00 00 0D 00 00 00 FE FF FF FF FE FF FF FF FE FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
"FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
};
RawDataBlockList data_blocks = new RawDataBlockList(new ByteArrayInputStream(RawDataUtil
.decode(raw_data_array)), POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
int[] bat_array = { 15 };
// need to initialize the block list with a block allocation
// table
new BlockAllocationTableReader(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 1, bat_array, 0, -2, data_blocks);
// Fake up a header
HeaderBlock header_block = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
header_block.setPropertyStart(0);
// get property table from the document
PropertyTable properties = new PropertyTable(header_block, data_blocks);
RootProperty root = properties.getRoot();
BlockList bl = SmallBlockTableReader.getSmallDocumentBlocks(
POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, data_blocks, root, 14);
assertNotNull(bl);
}
}

View File

@ -1,96 +0,0 @@
/* ====================================================================
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.poifs.storage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.OPOIFSDocument;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.property.RootProperty;
/**
* Class to test SmallBlockTableWriter functionality
*
* @author Marc Johnson
*/
public final class TestSmallBlockTableWriter extends TestCase {
public void testWritingConstructor() throws IOException {
List<OPOIFSDocument> documents = new ArrayList<>();
documents.add(
new OPOIFSDocument(
"doc340", new ByteArrayInputStream(new byte[ 340 ])));
documents.add(
new OPOIFSDocument(
"doc5000", new ByteArrayInputStream(new byte[ 5000 ])));
documents
.add(new OPOIFSDocument("doc0",
new ByteArrayInputStream(new byte[ 0 ])));
documents
.add(new OPOIFSDocument("doc1",
new ByteArrayInputStream(new byte[ 1 ])));
documents
.add(new OPOIFSDocument("doc2",
new ByteArrayInputStream(new byte[ 2 ])));
documents
.add(new OPOIFSDocument("doc3",
new ByteArrayInputStream(new byte[ 3 ])));
documents
.add(new OPOIFSDocument("doc4",
new ByteArrayInputStream(new byte[ 4 ])));
documents
.add(new OPOIFSDocument("doc5",
new ByteArrayInputStream(new byte[ 5 ])));
documents
.add(new OPOIFSDocument("doc6",
new ByteArrayInputStream(new byte[ 6 ])));
documents
.add(new OPOIFSDocument("doc7",
new ByteArrayInputStream(new byte[ 7 ])));
documents
.add(new OPOIFSDocument("doc8",
new ByteArrayInputStream(new byte[ 8 ])));
documents
.add(new OPOIFSDocument("doc9",
new ByteArrayInputStream(new byte[ 9 ])));
HeaderBlock header = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
RootProperty root = new PropertyTable(header).getRoot();
SmallBlockTableWriter sbtw = new SmallBlockTableWriter(
POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, documents,root);
BlockAllocationTableWriter bat = sbtw.getSBAT();
// 15 small blocks: 6 for doc340, 0 for doc5000 (too big), 0
// for doc0 (no storage needed), 1 each for doc1 through doc9
assertEquals(15 * 64, root.getSize());
// 15 small blocks rounds up to 2 big blocks
assertEquals(2, sbtw.countBlocks());
int start_block = 1000 + root.getStartBlock();
sbtw.setStartBlock(start_block);
assertEquals(start_block, root.getStartBlock());
}
}

View File

@ -1,223 +0,0 @@
/* ====================================================================
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.poifs.storage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.apache.poi.poifs.common.POIFSConstants;
/**
* Class to test SmallDocumentBlock functionality
*
* @author Marc Johnson
*/
public final class TestSmallDocumentBlock extends TestCase {
static final private byte[] _testdata;
static final private int _testdata_size = 2999;
static
{
_testdata = new byte[ _testdata_size ];
for (int j = 0; j < _testdata.length; j++)
{
_testdata[ j ] = ( byte ) j;
}
}
/**
* Test conversion from DocumentBlocks
*/
public void testConvert1()
throws IOException
{
ByteArrayInputStream stream = new ByteArrayInputStream(_testdata);
List<DocumentBlock> documents = new ArrayList<>();
while (true)
{
DocumentBlock block = new DocumentBlock(stream,POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
documents.add(block);
if (block.partiallyRead())
{
break;
}
}
SmallDocumentBlock[] results =
SmallDocumentBlock.convert(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,
documents.toArray(new DocumentBlock[ 0 ]), _testdata_size);
assertEquals("checking correct result size: ",
(_testdata_size + 63) / 64, results.length);
ByteArrayOutputStream output = new ByteArrayOutputStream();
for (SmallDocumentBlock result : results) {
result.writeBlocks(output);
}
byte[] output_array = output.toByteArray();
assertEquals("checking correct output size: ", 64 * results.length,
output_array.length);
int index = 0;
for (; index < _testdata_size; index++)
{
assertEquals("checking output " + index, _testdata[ index ],
output_array[ index ]);
}
for (; index < output_array.length; index++)
{
assertEquals("checking output " + index, ( byte ) 0xff,
output_array[ index ]);
}
}
/**
* Test conversion from byte array
*/
public void testConvert2()
throws IOException
{
for (int j = 0; j < 320; j++)
{
byte[] array = new byte[ j ];
for (int k = 0; k < j; k++)
{
array[ k ] = ( byte ) k;
}
SmallDocumentBlock[] blocks = SmallDocumentBlock.convert(
POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, array, 319);
assertEquals(5, blocks.length);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
for (SmallDocumentBlock block : blocks) {
block.writeBlocks(stream);
}
stream.close();
byte[] output = stream.toByteArray();
for (int k = 0; k < array.length; k++)
{
assertEquals(String.valueOf(k), array[ k ], output[ k ]);
}
for (int k = array.length; k < 320; k++)
{
assertEquals(String.valueOf(k), ( byte ) 0xFF, output[ k ]);
}
}
}
/**
* test fill
*/
public void testFill()
throws IOException
{
for (int j = 0; j <= 8; j++)
{
List<SmallDocumentBlock> blocks = new ArrayList<>();
for (int k = 0; k < j; k++)
{
blocks.add(new SmallDocumentBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS));
}
int result = SmallDocumentBlock.fill(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, blocks);
assertEquals("correct big block count: ", (j + 7) / 8, result);
assertEquals("correct small block count: ", 8 * result,
blocks.size());
for (int m = j; m < blocks.size(); m++)
{
BlockWritable block = blocks.get(m);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
block.writeBlocks(stream);
byte[] output = stream.toByteArray();
assertEquals("correct output size (block[ " + m + " ]): ",
64, output.length);
for (int n = 0; n < 64; n++)
{
assertEquals("correct value (block[ " + m + " ][ " + n
+ " ]): ", ( byte ) 0xff, output[ n ]);
}
}
}
}
/**
* test calcSize
*/
public void testCalcSize()
{
for (int j = 0; j < 10; j++)
{
assertEquals("testing " + j, j * 64,
SmallDocumentBlock.calcSize(j));
}
}
/**
* test extract method
*
* @exception IOException
*/
public void testExtract()
throws IOException
{
byte[] data = new byte[ 512 ];
int offset = 0;
for (int j = 0; j < 8; j++)
{
for (int k = 0; k < 64; k++)
{
data[ offset++ ] = ( byte ) (k + j);
}
}
RawDataBlock[] blocks =
{
new RawDataBlock(new ByteArrayInputStream(data))
};
List<SmallDocumentBlock> output = SmallDocumentBlock.extract(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,blocks);
offset = 0;
for (SmallDocumentBlock block : output)
{
byte[] out_data = block.getData();
assertEquals("testing block at offset " + offset, 64,
out_data.length);
for (byte b : out_data) {
assertEquals("testing byte at offset " + offset,
data[ offset ], b);
offset++;
}
}
}
}

View File

@ -1,67 +0,0 @@
/* ====================================================================
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.poifs.storage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.poi.poifs.common.POIFSConstants;
import junit.framework.TestCase;
/**
* Class to test SmallDocumentBlockList functionality
*
* @author Marc Johnson
*/
public final class TestSmallDocumentBlockList extends TestCase {
public void testConstructor() throws IOException {
byte[] data = new byte[ 2560 ];
for (int j = 0; j < 2560; j++)
{
data[ j ] = ( byte ) j;
}
ByteArrayInputStream stream = new ByteArrayInputStream(data);
RawDataBlock[] blocks = new RawDataBlock[ 5 ];
for (int j = 0; j < 5; j++)
{
blocks[ j ] = new RawDataBlock(stream);
}
SmallDocumentBlockList sdbl =
new SmallDocumentBlockList(SmallDocumentBlock.extract(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,blocks));
// proof we added the blocks
for (int j = 0; j < 40; j++)
{
sdbl.remove(j);
}
try
{
sdbl.remove(41);
fail("there should have been an Earth-shattering ka-boom!");
}
catch (IOException ignored)
{
// it better have thrown one!!
}
}
}