From: Andreas Beeker Date: Sun, 26 Aug 2018 11:55:00 +0000 (+0000) Subject: #62649 - Remove OPOIFS X-Git-Tag: REL_4_0_0_FINAL~14 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=96d5fab4836225c0aebb0d71bff4a04ae98858e0;p=poi.git #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 --- diff --git a/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java b/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java index 77859d8adb..d494e256fb 100644 --- a/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java +++ b/src/examples/src/org/apache/poi/hpsf/examples/CopyCompare.java @@ -20,8 +20,6 @@ package org.apache.poi.hpsf.examples; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -30,19 +28,21 @@ import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; +import org.apache.poi.hpsf.DocumentSummaryInformation; 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.SummaryInformation; +import org.apache.poi.hpsf.UnexpectedPropertySetTypeException; import org.apache.poi.hpsf.WritingNotSupportedException; 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.filesystem.DirectoryEntry; -import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.DocumentInputStream; -import org.apache.poi.poifs.filesystem.Entry; +import org.apache.poi.poifs.filesystem.EntryUtils; import org.apache.poi.poifs.filesystem.POIFSDocumentPath; import org.apache.poi.poifs.filesystem.POIFSFileSystem; 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. * Details like the ordering of the properties do not matter.

*/ -public class CopyCompare { +public final class CopyCompare { + private CopyCompare() {} + /** - *

Runs the example program. The application expects one or two - * arguments:

- *

+ * Runs the example program. The application expects one or two arguments: + * *

    - *

    - *

  1. The first argument is the disk file name of the POI filesystem to - * copy.

  2. - *

    - *

  3. The second argument is optional. If it is given, it is the name of + *

  4. The first argument is the disk file name of the POI filesystem to copy.
  5. + *
  6. 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 * not given, the copy will be written to a temporary file which will be - * deleted at the end of the program.

  7. - *

    + * deleted at the end of the program. *

* * @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 UnsupportedEncodingException if a character encoding is not * supported. */ public static void main(final String[] args) - throws NoPropertySetStreamException, MarkUnsupportedException, - UnsupportedEncodingException, IOException { + throws UnsupportedEncodingException, IOException { String originalFileName = null; String copyFileName = null; @@ -120,10 +111,9 @@ public class CopyCompare { final CopyFile cf = new CopyFile(copyFileName); r.registerListener(cf); r.setNotifyEmptyDirectories(true); - try (FileInputStream fis = new FileInputStream(originalFileName)) { - r.read(fis); - } - + + r.read(new File(originalFileName)); + /* Write the new POIFS to disk. */ cf.close(); @@ -133,124 +123,10 @@ public class CopyCompare { POIFSFileSystem cpfs = new POIFSFileSystem(new File(copyFileName))) { final DirectoryEntry oRoot = opfs.getRoot(); final DirectoryEntry cRoot = cpfs.getRoot(); - final StringBuffer messages = new StringBuffer(); - if (equal(oRoot, cRoot, messages)) { - System.out.println("Equal"); - } else { - System.out.println("Not equal: " + messages); - } - } - } - - - /** - *

Compares two {@link DirectoryEntry} instances of a POI file system. - * The directories must contain the same streams with the same names and - * contents.

- * - * @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 true if the directories are equal, else - * false. - * @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; - } - - - /** - *

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.

- * - * @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 true if the documents are equal, else - * false. - * @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); - } + System.out.println(EntryUtils.areDirectoriesIdentical(oRoot, cRoot) ? "Equal" : "Not equal"); } - return true; } - /** *

This class does all the work. Its method {@link * #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 * be written to. */ - public CopyFile(final String dstName) { + CopyFile(final String dstName) { this.dstName = dstName; poiFs = new POIFSFileSystem(); } @@ -332,7 +208,7 @@ public class CopyCompare { /** - *

Writes a {@link PropertySet} to a POI filesystem.

+ * Writes a {@link PropertySet} to a POI filesystem. * * @param poiFs The POI filesystem to write to. * @param path The file's path in the POI filesystem. @@ -345,14 +221,25 @@ public class CopyCompare { final PropertySet ps) throws WritingNotSupportedException, IOException { 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()); } /** - *

Copies the bytes from a {@link DocumentInputStream} to a new - * stream in a POI filesystem.

+ * Copies the bytes from a {@link DocumentInputStream} to a new + * stream in a POI filesystem. * * @param poiFs The POI filesystem to write to. * @param path The source document's path. @@ -385,9 +272,9 @@ public class CopyCompare { /** - *

Writes the POI file system to a disk file.

+ * Writes the POI file system to a disk file. */ - public void close() throws FileNotFoundException, IOException { + public void close() throws IOException { out = new FileOutputStream(dstName); poiFs.writeFilesystem(out); out.close(); @@ -456,11 +343,7 @@ public class CopyCompare { /* This exception will be thrown if the directory already * exists. However, since we have full control about directory * creation we can ensure that this will never happen. */ - ex.printStackTrace(System.err); - 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); + throw new RuntimeException(ex); } } } diff --git a/src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java b/src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java index 2212e81466..9282b7cd32 100644 --- a/src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java +++ b/src/examples/src/org/apache/poi/hpsf/examples/ReadCustomPropertySets.java @@ -17,7 +17,7 @@ package org.apache.poi.hpsf.examples; -import java.io.FileInputStream; +import java.io.File; import java.io.IOException; import java.util.List; @@ -37,8 +37,9 @@ import org.apache.poi.util.HexDump; * *

Explanations can be found in the HPSF HOW-TO.

*/ -public class ReadCustomPropertySets -{ +public final class ReadCustomPropertySets { + + private ReadCustomPropertySets() {} /** *

Runs the example program.

@@ -54,7 +55,7 @@ public class ReadCustomPropertySets /* Register a listener for *all* documents. */ 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); } - static String hex(final byte[] bytes) + private static String hex(final byte[] bytes) { return HexDump.dump(bytes, 0L, 0); } diff --git a/src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java b/src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java index 7e0c447f07..38313a14c5 100644 --- a/src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java +++ b/src/examples/src/org/apache/poi/hpsf/examples/ReadTitle.java @@ -17,7 +17,7 @@ package org.apache.poi.hpsf.examples; -import java.io.FileInputStream; +import java.io.File; import java.io.IOException; import org.apache.poi.hpsf.PropertySetFactory; @@ -33,8 +33,10 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; * *

Explanations can be found in the HPSF HOW-TO.

*/ -public class ReadTitle +public final class ReadTitle { + private ReadTitle() {} + /** *

Runs the example program.

* @@ -47,7 +49,7 @@ public class ReadTitle final String filename = args[0]; POIFSReader r = new POIFSReader(); r.registerListener(new MyPOIFSReaderListener(), SummaryInformation.DEFAULT_STREAM_NAME); - r.read(new FileInputStream(filename)); + r.read(new File(filename)); } diff --git a/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java b/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java index b674ec2d1a..36c6f8287a 100644 --- a/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java +++ b/src/examples/src/org/apache/poi/hpsf/examples/WriteAuthorAndTitle.java @@ -19,8 +19,7 @@ package org.apache.poi.hpsf.examples; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.FileNotFoundException; +import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -28,7 +27,15 @@ import java.io.OutputStream; import java.util.HashMap; 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.poifs.eventfilesystem.POIFSReader; import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; @@ -72,8 +79,9 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem; * *

Further explanations can be found in the HPSF HOW-TO.

*/ -public class WriteAuthorAndTitle -{ +public final class WriteAuthorAndTitle { + private WriteAuthorAndTitle() {} + /** *

Runs the example program.

* @@ -101,10 +109,8 @@ public class WriteAuthorAndTitle final POIFSReader r = new POIFSReader(); final ModifySICopyTheRest msrl = new ModifySICopyTheRest(dstName); r.registerListener(msrl); - FileInputStream fis = new FileInputStream(srcName); - r.read(fis); - fis.close(); - + r.read(new File(srcName)); + /* Write the new POIFS to disk. */ msrl.close(); } @@ -127,14 +133,14 @@ public class WriteAuthorAndTitle /** - *

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 - * be written to once it is complete.

+ * be written to once it is complete. * * @param dstName The name of the disk file the destination POIFS is to * be written to. */ - public ModifySICopyTheRest(final String dstName) + ModifySICopyTheRest(final String dstName) { this.dstName = dstName; poiFs = new POIFSFileSystem(); @@ -142,8 +148,8 @@ public class WriteAuthorAndTitle /** - *

The method is called by POI's eventing API for each file in the - * origin POIFS.

+ * The method is called by POI's eventing API for each file in the + * origin POIFS. */ @Override public void processPOIFSReaderEvent(final POIFSReaderEvent event) @@ -213,7 +219,7 @@ public class WriteAuthorAndTitle * @param si The property set. It should be a summary information * property set. */ - public void editSI(final POIFSFileSystem poiFs, + void editSI(final POIFSFileSystem poiFs, final POIFSDocumentPath path, final String name, final PropertySet si) @@ -297,9 +303,9 @@ public class WriteAuthorAndTitle /** - *

Writes the POI file system to a disk file.

+ * Writes the POI file system to a disk file. */ - public void close() throws FileNotFoundException, IOException + public void close() throws IOException { out = new FileOutputStream(dstName); poiFs.writeFilesystem(out); diff --git a/src/examples/src/org/apache/poi/poifs/poibrowser/POIBrowser.java b/src/examples/src/org/apache/poi/poifs/poibrowser/POIBrowser.java index 586243528f..a70f5edd00 100644 --- a/src/examples/src/org/apache/poi/poifs/poibrowser/POIBrowser.java +++ b/src/examples/src/org/apache/poi/poifs/poibrowser/POIBrowser.java @@ -19,7 +19,7 @@ package org.apache.poi.poifs.poibrowser; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.io.FileInputStream; +import java.io.File; import java.io.IOException; import javax.swing.JFrame; @@ -42,12 +42,6 @@ import org.apache.poi.poifs.eventfilesystem.POIFSReader; public class POIBrowser extends JFrame { - /** - *

The tree's root node must be visible to all methods.

- */ - protected MutableTreeNode rootNode; - - /** *

Takes a bunch of file names as command line parameters, @@ -59,8 +53,6 @@ public class POIBrowser extends JFrame new POIBrowser().run(args); } - - protected void run(String[] args) { addWindowListener(new WindowAdapter() @@ -74,8 +66,11 @@ public class POIBrowser extends JFrame /* Create the tree model with a root node. The latter is * invisible but it must be present because a tree model - * always needs a root. */ - rootNode = new DefaultMutableTreeNode("POI Filesystems"); + * always needs a root. + * + * The tree's root node must be visible to all methods. + */ + MutableTreeNode rootNode = new DefaultMutableTreeNode("POI Filesystems"); DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); /* Create the tree UI element. */ @@ -85,10 +80,10 @@ public class POIBrowser extends JFrame /* Add the POI filesystems to the tree. */ int displayedFiles = 0; for (final String filename : args) { - try (FileInputStream fis = new FileInputStream(filename)) { + try { POIFSReader r = new POIFSReader(); r.registerListener(new TreeReaderListener(filename, rootNode)); - r.read(fis); + r.read(new File(filename)); displayedFiles++; } catch (IOException ex) { System.err.println(filename + ": " + ex); diff --git a/src/java/org/apache/poi/POIDocument.java b/src/java/org/apache/poi/POIDocument.java index 4d86f13927..c2c19fcea6 100644 --- a/src/java/org/apache/poi/POIDocument.java +++ b/src/java/org/apache/poi/POIDocument.java @@ -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.DocumentInputStream; 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.util.IOUtils; import org.apache.poi.util.Internal; @@ -75,14 +74,6 @@ public abstract class POIDocument implements Closeable { 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 * @@ -195,6 +186,7 @@ public abstract class POIDocument implements Closeable { * @param setName The property to read * @return The value of the given property or null if it wasn't found. */ + @SuppressWarnings("WeakerAccess") protected PropertySet getPropertySet(String setName) throws IOException { return getPropertySet(setName, getEncryptionInfo()); } @@ -207,6 +199,7 @@ public abstract class POIDocument implements Closeable { * @param encryptionInfo the encryption descriptor in case of cryptoAPI encryption * @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 { DirectoryNode dirNode = directory; @@ -329,7 +322,7 @@ public abstract class POIDocument implements Closeable { * @throws IOException if an error when writing to the * {@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 { PropertySet mSet = new PropertySet(set); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); @@ -420,8 +413,9 @@ public abstract class POIDocument implements Closeable { /** * Closes the underlying {@link NPOIFSFileSystem} from which * the document was read, if any. Has no effect on documents - * opened from an InputStream, or newly created ones. - *

Once close() has been called, no further operations + * opened from an InputStream, or newly created ones.

+ * + * Once {@code close()} has been called, no further operations * should be called on the document. */ @Override @@ -468,13 +462,10 @@ public abstract class POIDocument implements Closeable { * to a new POIFSFileSystem * * @param newDirectory the new directory - * @return the old/previous directory */ @Internal - protected DirectoryNode replaceDirectory(DirectoryNode newDirectory) { - DirectoryNode dn = directory; + protected void replaceDirectory(DirectoryNode newDirectory) { directory = newDirectory; - return dn; } /** diff --git a/src/java/org/apache/poi/POIReadOnlyDocument.java b/src/java/org/apache/poi/POIReadOnlyDocument.java index 3b3eca588d..ef4956f525 100644 --- a/src/java/org/apache/poi/POIReadOnlyDocument.java +++ b/src/java/org/apache/poi/POIReadOnlyDocument.java @@ -21,8 +21,6 @@ import java.io.OutputStream; import org.apache.poi.poifs.filesystem.DirectoryNode; 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 */ public abstract class POIReadOnlyDocument extends POIDocument { - public POIReadOnlyDocument(DirectoryNode dir) { + protected POIReadOnlyDocument(DirectoryNode dir) { super(dir); } - public POIReadOnlyDocument(NPOIFSFileSystem fs) { - super(fs); - } - public POIReadOnlyDocument(OPOIFSFileSystem fs) { - super(fs); - } - public POIReadOnlyDocument(POIFSFileSystem fs) { + protected POIReadOnlyDocument(NPOIFSFileSystem fs) { super(fs); } diff --git a/src/java/org/apache/poi/extractor/OLE2ExtractorFactory.java b/src/java/org/apache/poi/extractor/OLE2ExtractorFactory.java index fda090729e..8b2e7bba2c 100644 --- a/src/java/org/apache/poi/extractor/OLE2ExtractorFactory.java +++ b/src/java/org/apache/poi/extractor/OLE2ExtractorFactory.java @@ -26,20 +26,14 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import org.apache.poi.EncryptedDocumentException; import org.apache.poi.hssf.OldExcelFormatException; import org.apache.poi.hssf.extractor.EventBasedExcelExtractor; 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.DirectoryNode; import org.apache.poi.poifs.filesystem.Entry; 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.util.IOUtils; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -50,24 +44,24 @@ import org.apache.poi.util.POILogger; *

Note 1 - will fail for many file formats if the POI Scratchpad jar is * not present on the runtime classpath

*

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.

*

Note 3 - rather than using this, for most cases you would be better * off switching to Apache Tika instead!

*/ @SuppressWarnings("WeakerAccess") -public class OLE2ExtractorFactory { +public final class OLE2ExtractorFactory { private static final POILogger LOGGER = POILogFactory.getLogger(OLE2ExtractorFactory.class); /** Should this thread prefer event based over usermodel based extractors? */ - private static final ThreadLocal threadPreferEventExtractors = new ThreadLocal() { - @Override - protected Boolean initialValue() { return Boolean.FALSE; } - }; + private static final ThreadLocal threadPreferEventExtractors = ThreadLocal.withInitial(() -> Boolean.FALSE); /** Should all threads prefer event based over usermodel based extractors? */ private static Boolean allPreferEventExtractors; + private OLE2ExtractorFactory() { + } + /** * Should this thread prefer event based over usermodel based extractors? * (usermodel extractors tend to be more accurate, but use more memory) @@ -113,16 +107,16 @@ public class OLE2ExtractorFactory { return threadPreferEventExtractors.get(); } + @SuppressWarnings("unchecked") public static T createExtractor(POIFSFileSystem fs) throws IOException { return (T)createExtractor(fs.getRoot()); } + @SuppressWarnings("unchecked") public static T createExtractor(NPOIFSFileSystem fs) throws IOException { return (T)createExtractor(fs.getRoot()); } - public static T createExtractor(OPOIFSFileSystem fs) throws IOException { - return (T)createExtractor(fs.getRoot()); - } + @SuppressWarnings("unchecked") public static T createExtractor(InputStream input) throws IOException { Class cls = getOOXMLClass(); if (cls != null) { @@ -165,7 +159,7 @@ public class OLE2ExtractorFactory { /** * Create the Extractor, if possible. Generally needs the Scratchpad jar. * 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 { // 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 * {@link POITextExtractor} for each embedded file. */ + @SuppressWarnings("unused") public static POITextExtractor[] getEmbededDocsTextExtractors(POIOLE2TextExtractor ext) throws IOException { @@ -254,40 +249,11 @@ public class OLE2ExtractorFactory { for (InputStream nonPOIF : nonPOIFS) { try { 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) { // Ignore, invalid format LOGGER.log(POILogger.WARN, xe); } } - return e.toArray(new POITextExtractor[e.size()]); - } - - 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); - } + return e.toArray(new POITextExtractor[0]); } } diff --git a/src/java/org/apache/poi/hpsf/HPSFPropertiesOnlyDocument.java b/src/java/org/apache/poi/hpsf/HPSFPropertiesOnlyDocument.java index 3f6731c51d..868f1bf36e 100644 --- a/src/java/org/apache/poi/hpsf/HPSFPropertiesOnlyDocument.java +++ b/src/java/org/apache/poi/hpsf/HPSFPropertiesOnlyDocument.java @@ -26,7 +26,6 @@ import org.apache.poi.POIDocument; import org.apache.poi.poifs.filesystem.EntryUtils; import org.apache.poi.poifs.filesystem.FilteringDirectoryNode; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; -import org.apache.poi.poifs.filesystem.OPOIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** @@ -39,9 +38,6 @@ public class HPSFPropertiesOnlyDocument extends POIDocument { public HPSFPropertiesOnlyDocument(NPOIFSFileSystem fs) { super(fs.getRoot()); } - public HPSFPropertiesOnlyDocument(OPOIFSFileSystem fs) { - super(fs); - } public HPSFPropertiesOnlyDocument(POIFSFileSystem fs) { super(fs); } @@ -60,24 +56,18 @@ public class HPSFPropertiesOnlyDocument extends POIDocument { * Write out, with any properties changes, but nothing else */ public void write(File newFile) throws IOException { - POIFSFileSystem fs = POIFSFileSystem.create(newFile); - try { + try (POIFSFileSystem fs = POIFSFileSystem.create(newFile)) { write(fs); fs.writeFilesystem(); - } finally { - fs.close(); } } /** * Write out, with any properties changes, but nothing else */ public void write(OutputStream out) throws IOException { - NPOIFSFileSystem fs = new NPOIFSFileSystem(); - try { + try (NPOIFSFileSystem fs = new NPOIFSFileSystem()) { write(fs); fs.writeFilesystem(out); - } finally { - fs.close(); } } diff --git a/src/java/org/apache/poi/hpsf/Property.java b/src/java/org/apache/poi/hpsf/Property.java index df38d7a597..8878497dc3 100644 --- a/src/java/org/apache/poi/hpsf/Property.java +++ b/src/java/org/apache/poi/hpsf/Property.java @@ -345,9 +345,13 @@ public class Property { * @return the truncated size with a maximum of 4 bytes shorter (3 bytes + trailing 0 of strings) */ private static int unpaddedLength(byte[] buf) { - int len; - for (len = buf.length; len > 0 && len > buf.length-4 && buf[len-1] == 0; len--); - return len; + final int end = (buf.length-(buf.length+3)%4); + for (int i = buf.length; i>end; i--) { + if (buf[i-1] != 0) { + return i; + } + } + return end; } diff --git a/src/java/org/apache/poi/hpsf/PropertySet.java b/src/java/org/apache/poi/hpsf/PropertySet.java index 77621419ba..70c0a1bf16 100644 --- a/src/java/org/apache/poi/hpsf/PropertySet.java +++ b/src/java/org/apache/poi/hpsf/PropertySet.java @@ -34,8 +34,11 @@ import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.util.CodePageUtil; import org.apache.poi.util.IOUtils; import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianConsts; +import org.apache.poi.util.LittleEndianOutputStream; import org.apache.poi.util.NotImplemented; +import org.apache.poi.util.Removal; /** * 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 * stream. - * @throws MarkUnsupportedException - * if the stream does not support the {@link InputStream#markSupported} method. * @throws IOException * if the {@link InputStream} cannot be accessed as needed. * @exception NoPropertySetStreamException @@ -185,8 +186,7 @@ public class PropertySet { * if a character encoding is not supported. */ public PropertySet(final InputStream stream) - throws NoPropertySetStreamException, MarkUnsupportedException, - IOException, UnsupportedEncodingException { + throws NoPropertySetStreamException, IOException { if (!isPropertySetStream(stream)) { throw new NoPropertySetStreamException(); } @@ -266,6 +266,7 @@ public class PropertySet { * * @param byteOrder The property set stream's low-level "byte order" field. */ + @SuppressWarnings("WeakerAccess") public void setByteOrder(int byteOrder) { this.byteOrder = byteOrder; } @@ -298,6 +299,7 @@ public class PropertySet { * * @param osVersion The property set stream's low-level "OS version" field. */ + @SuppressWarnings("WeakerAccess") public void setOSVersion(int osVersion) { this.osVersion = osVersion; } @@ -315,6 +317,7 @@ public class PropertySet { * * @param classID The property set stream's low-level "class ID" field. */ + @SuppressWarnings("WeakerAccess") public void setClassID(ClassID classID) { this.classID = classID; } @@ -374,12 +377,10 @@ public class PropertySet { * {@link InputStream#mark} method. * @return {@code true} if the stream is a property set * 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 */ public static boolean isPropertySetStream(final InputStream stream) - throws MarkUnsupportedException, IOException { + throws IOException { /* * Read at most this many bytes. */ @@ -408,30 +409,34 @@ public class PropertySet { * @return {@code true} if the byte array is a property set * stream, {@code false} if not. */ + @SuppressWarnings({"unused", "WeakerAccess"}) 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 * there. */ - int o = offset; - final int byteOrder = LittleEndian.getUShort(src, o); - o += LittleEndianConsts.SHORT_SIZE; - if (byteOrder != BYTE_ORDER_ASSERTION) { - return false; - } - final int format = LittleEndian.getUShort(src, o); - o += LittleEndianConsts.SHORT_SIZE; - if (format != FORMAT_ASSERTION) { + try { + final int byteOrder = leis.readUShort(); + 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; } - // 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) throws UnsupportedEncodingException { /* FIXME (3): Ensure that at most "length" bytes are read. */ - + /* * Read the stream's header fields. */ @@ -504,50 +509,60 @@ public class PropertySet { * @exception WritingNotSupportedException if HPSF does not yet support * writing a property's variant type. */ - public void write(final OutputStream out) - throws WritingNotSupportedException, IOException { + public void write(final OutputStream out) throws IOException, WritingNotSupportedException { + + 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. */ final int nrSections = getSectionCount(); /* Write the property set's header. */ - LittleEndian.putShort(out, (short) getByteOrder()); - LittleEndian.putShort(out, (short) getFormat()); - LittleEndian.putInt(getOSVersion(), out); - putClassId(out, getClassID()); - LittleEndian.putInt(nrSections, out); - int offset = OFFSET_HEADER; + leos.writeShort(getByteOrder()); + leos.writeShort(getFormat()); + leos.writeInt(getOSVersion()); + putClassId(bos, getClassID()); + leos.writeInt(nrSections); + + assert(bos.size() == OFFSET_HEADER); + + final int[][] offsets = new int[getSectionCount()][2]; /* 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 * section's offset relative to the beginning of the stream. */ - offset += nrSections * (ClassID.LENGTH + LittleEndianConsts.INT_SIZE); - final int sectionsBegin = offset; + int secCnt = 0; for (final Section section : getSections()) { final ClassID formatID = section.getFormatID(); if (formatID == null) { throw new NoFormatIDException(); } - putClassId(out, formatID); - LittleEndian.putUInt(offset, out); - try { - offset += section.getSize(); - } catch (HPSFRuntimeException ex) { - final Throwable cause = ex.getReason(); - if (cause instanceof UnsupportedEncodingException) { - throw new IllegalPropertySetDataException(cause); - } - throw ex; - } + putClassId(bos, formatID); + offsets[secCnt++][0] = bos.size(); + // offset dummy - filled later + leos.writeInt(-1); } /* Write the sections themselves. */ - offset = sectionsBegin; + secCnt = 0; for (final Section section : getSections()) { - offset += section.write(out); + offsets[secCnt++][1] = bos.size(); + section.write(bos); } - - /* Indicate that we're done */ - out.close(); + + byte[] result = bos.toByteArray(); + 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. * @throws IOException if an I/O exception occurs. */ - public InputStream toInputStream() throws IOException, WritingNotSupportedException { - final ByteArrayOutputStream psStream = new ByteArrayOutputStream(); - try { - write(psStream); - } finally { - psStream.close(); - } - final byte[] streamData = psStream.toByteArray(); - return new ByteArrayInputStream(streamData); + public InputStream toInputStream() throws WritingNotSupportedException, IOException { + return new ByteArrayInputStream(toBytes()); } /** @@ -605,7 +613,7 @@ public class PropertySet { * * @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); return getPropertyStringValue(propertyValue); } @@ -724,7 +732,7 @@ public class PropertySet { * @throws NoSingleSectionException if the {@link PropertySet} has * 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); } @@ -742,7 +750,7 @@ public class PropertySet { * @throws NoSingleSectionException if the {@link PropertySet} has * 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); } @@ -774,6 +782,7 @@ public class PropertySet { * * @return The {@link PropertySet}'s first section. */ + @SuppressWarnings("WeakerAccess") public Section getFirstSection() { if (sections.isEmpty()) { 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. * * @return The singleSection value + * + * @deprecated superfluous convenience method */ + @Deprecated + @Removal(version="5.0.0") public Section getSingleSection() { final int sectionCount = getSectionCount(); if (sectionCount != 1) { @@ -809,7 +822,7 @@ public class PropertySet { */ @Override public boolean equals(final Object o) { - if (o == null || !(o instanceof PropertySet)) { + if (!(o instanceof PropertySet)) { return false; } final PropertySet ps = (PropertySet) o; @@ -877,27 +890,28 @@ public class PropertySet { } - protected void remove1stProperty(long id) { + void remove1stProperty(long id) { getFirstSection().removeProperty(id); } - protected void set1stProperty(long id, String value) { + void set1stProperty(long id, String value) { getFirstSection().setProperty((int)id, value); } - protected void set1stProperty(long id, int value) { + void set1stProperty(long id, int value) { getFirstSection().setProperty((int)id, value); } - protected void set1stProperty(long id, boolean value) { + void set1stProperty(long id, boolean 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); } - 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]; n.write(b, 0); out.write(b, 0, b.length); diff --git a/src/java/org/apache/poi/hpsf/Section.java b/src/java/org/apache/poi/hpsf/Section.java index bcacfb3348..1411d0490f 100644 --- a/src/java/org/apache/poi/hpsf/Section.java +++ b/src/java/org/apache/poi/hpsf/Section.java @@ -36,6 +36,7 @@ import org.apache.poi.util.IOUtils; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianByteArrayInputStream; import org.apache.poi.util.LittleEndianConsts; +import org.apache.poi.util.LittleEndianOutputStream; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -81,7 +82,7 @@ public class Section { * #getPropertyIntValue} or {@link #getProperty} tried to access a * property that was not available, else {@code false}. */ - private boolean wasNull; + private transient boolean wasNull; /** * 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 * are in big-endian format. */ + @SuppressWarnings("WeakerAccess") public void setFormatID(final byte[] formatID) { ClassID fid = getFormatID(); if (fid == null) { @@ -325,7 +327,7 @@ public class Section { * @return This section's properties. */ 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 */ 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 */ 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 */ 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 */ - protected int getPropertyIntValue(final long id) { + int getPropertyIntValue(final long id) { final Number i; final Object o = getProperty(id); if (o == null) { @@ -513,9 +515,9 @@ public class Section { * * @return The property's value */ - protected boolean getPropertyBooleanValue(final int id) { + boolean getPropertyBooleanValue(final int 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 Variant */ + @SuppressWarnings("unused") 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 * property that was not available, else {@code false}. */ + @SuppressWarnings("WeakerAccess") public boolean wasNull() { return wasNull; } @@ -674,7 +678,7 @@ public class Section { for (Long id : propIds) { Property p1 = 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; } } @@ -683,7 +687,7 @@ public class Section { Map d1 = getDictionary(); Map 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 */ + @SuppressWarnings("WeakerAccess") public void removeProperty(final long id) { if (properties.remove(id) != null) { sectionBytes.reset(); @@ -731,60 +736,54 @@ public class Section { codepage = Property.DEFAULT_CODEPAGE; } - /* The properties are written to this stream. */ - final ByteArrayOutputStream propertyStream = new ByteArrayOutputStream(); + final int[][] offsets = new int[properties.size()][2]; + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + final LittleEndianOutputStream leos = new LittleEndianOutputStream(bos); - /* The property list is established here. After each property that has - * been written to "propertyStream", a property list entry is written to - * "propertyListStream". */ - final ByteArrayOutputStream propertyListStream = new ByteArrayOutputStream(); + /* Write the section's length - dummy value, fixed later */ + leos.writeInt(-1); - /* Maintain the current position in the list. */ - int position = 0; + /* Write the section's number of properties: */ + 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 * streams: */ + propCnt = 0; for (Property p : properties.values()) { - final long id = p.getID(); - - /* Write the property list entry. */ - LittleEndian.putUInt(id, propertyListStream); - LittleEndian.putUInt(position, propertyListStream); - + offsets[propCnt++][1] = bos.size(); /* 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 * dictionary which has an implicit type only and an explicit * value. */ - if (id != 0) { + if (p.getID() != 0) { /* Write the property and update the position to the next * property. */ - position += p.write(propertyStream, codepage); + p.write(bos, codepage); } else { - position += writeDictionary(propertyStream, codepage); + writeDictionary(bos, codepage); } } - /* Write the section: */ - int streamLength = LittleEndianConsts.INT_SIZE * 2 + propertyListStream.size() + propertyStream.size(); - - /* Write the section's length: */ - LittleEndian.putInt(streamLength, out); + byte[] result = bos.toByteArray(); + LittleEndian.putInt(result, 0, bos.size()); - /* Write the section's number of properties: */ - LittleEndian.putInt(getPropertyCount(), out); - - /* Write the property list: */ - propertyListStream.writeTo(out); + for (int[] off : offsets) { + LittleEndian.putUInt(result, off[0], off[1]); + } - /* Write the properties: */ - propertyStream.writeTo(out); + out.write(result); - return streamLength; + return bos.size(); } /** @@ -795,12 +794,8 @@ public class Section { * @param codepage The codepage of the string values. * * @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) - throws UnsupportedEncodingException { + private boolean readDictionary(LittleEndianByteArrayInputStream leis, final int length, final int codepage) { Map dic = new HashMap<>(); /* @@ -863,13 +858,12 @@ public class Section { * * @param out The output stream to write to. * @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. */ - private int writeDictionary(final OutputStream out, final int codepage) + private void writeDictionary(final OutputStream out, final int codepage) throws IOException { final byte padding[] = new byte[4]; - Map dic = getDictionary(); + final Map dic = getDictionary(); LittleEndian.putUInt(dic.size(), out); int length = LittleEndianConsts.INT_SIZE; @@ -878,26 +872,23 @@ public class Section { LittleEndian.putUInt(ls.getKey(), out); length += LittleEndianConsts.INT_SIZE; - String value = ls.getValue()+"\0"; - LittleEndian.putUInt( value.length(), out ); + final String value = ls.getValue()+"\0"; + 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; - byte bytes[] = CodePageUtil.getBytesInCodePage(value, codepage); out.write(bytes); length += bytes.length; - if (codepage == CodePageUtil.CP_UNICODE) { - int pad = (4 - (length & 0x3)) & 0x3; - out.write(padding, 0, pad); - length += pad; - } + final int pad = (codepage == CodePageUtil.CP_UNICODE) ? ((4 - (length & 0x3)) & 0x3) : 0; + out.write(padding, 0, pad); + length += pad; } - int pad = (4 - (length & 0x3)) & 0x3; + final int pad = (4 - (length & 0x3)) & 0x3; out.write(padding, 0, pad); - length += pad; - - return length; } /** diff --git a/src/java/org/apache/poi/poifs/common/package-info.java b/src/java/org/apache/poi/poifs/common/package-info.java new file mode 100644 index 0000000000..2df44254bd --- /dev/null +++ b/src/java/org/apache/poi/poifs/common/package-info.java @@ -0,0 +1,21 @@ +/* ==================================================================== + 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. +==================================================================== */ + +/** + * common package contains constants and other classes shared across all POIFS subpackages + */ +package org.apache.poi.poifs.common; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/common/package.html b/src/java/org/apache/poi/poifs/common/package.html deleted file mode 100644 index da2edf1959..0000000000 --- a/src/java/org/apache/poi/poifs/common/package.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - -common package contains constants and other classes shared across all POIFS subpackages - -

Related Documentation

- -For overviews, tutorials, examples, guides, and tool documentation, please see: - - - - diff --git a/src/java/org/apache/poi/poifs/crypt/Decryptor.java b/src/java/org/apache/poi/poifs/crypt/Decryptor.java index da746d896e..0af59dce3d 100644 --- a/src/java/org/apache/poi/poifs/crypt/Decryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/Decryptor.java @@ -27,7 +27,6 @@ import javax.crypto.spec.SecretKeySpec; import org.apache.poi.EncryptedDocumentException; import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; -import org.apache.poi.poifs.filesystem.OPOIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem; 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 block the block index, e.g. the persist/slide id (hslf) * @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) throws GeneralSecurityException { @@ -126,10 +125,6 @@ public abstract class Decryptor implements Cloneable { return getDataStream(fs.getRoot()); } - public InputStream getDataStream(OPOIFSFileSystem fs) throws IOException, GeneralSecurityException { - return getDataStream(fs.getRoot()); - } - public InputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException { return getDataStream(fs.getRoot()); } @@ -147,6 +142,7 @@ public abstract class Decryptor implements Cloneable { return integrityHmacKey; } + @SuppressWarnings("unused") public byte[] getIntegrityHmacValue() { return integrityHmacValue; } @@ -167,6 +163,7 @@ public abstract class Decryptor implements Cloneable { this.integrityHmacValue = (integrityHmacValue == null) ? null : integrityHmacValue.clone(); } + @SuppressWarnings("unused") protected int getBlockSizeInBytes() { return encryptionInfo.getHeader().getBlockSize(); } diff --git a/src/java/org/apache/poi/poifs/crypt/EncryptionInfo.java b/src/java/org/apache/poi/poifs/crypt/EncryptionInfo.java index df08b3cf5b..eee1531622 100644 --- a/src/java/org/apache/poi/poifs/crypt/EncryptionInfo.java +++ b/src/java/org/apache/poi/poifs/crypt/EncryptionInfo.java @@ -27,7 +27,6 @@ import java.io.IOException; import org.apache.poi.EncryptedDocumentException; import org.apache.poi.poifs.filesystem.DirectoryNode; 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.util.BitField; 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. * The encryption of document properties is specified in section 2.3.5.4. */ + @SuppressWarnings("WeakerAccess") public static final BitField flagDocProps = BitFieldFactory.getInstance(0x08); /** * 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. */ + @SuppressWarnings("WeakerAccess") public static final BitField flagExternal = BitFieldFactory.getInstance(0x10); /** @@ -81,13 +82,6 @@ public class EncryptionInfo implements Cloneable { this(fs.getRoot()); } - /** - * Opens for decryption - */ - public EncryptionInfo(OPOIFSFileSystem fs) throws IOException { - this(fs.getRoot()); - } - /** * Opens for decryption */ @@ -167,11 +161,11 @@ public class EncryptionInfo implements Cloneable { * * @param encryptionMode see {@link EncryptionMode} for values, {@link EncryptionMode#cryptoAPI} is for * internal use only, as it's record based - * @param cipherAlgorithm - * @param hashAlgorithm - * @param keyBits - * @param blockSize - * @param chainingMode + * @param cipherAlgorithm the cipher algorithm + * @param hashAlgorithm the hash algorithm + * @param keyBits the bit count of the key + * @param blockSize the size of a cipher block + * @param chainingMode the chaining mode * * @throws EncryptedDocumentException if the given parameters mismatch, e.g. only certain combinations * of keyBits, blockSize are allowed for a given {@link CipherAlgorithm} @@ -211,10 +205,11 @@ public class EncryptionInfo implements Cloneable { * * @param encryptionMode the encryption mode * @return an encryption info builder - * @throws ClassNotFoundException - * @throws IllegalAccessException - * @throws InstantiationException + * @throws ClassNotFoundException if the builder class is not on the classpath + * @throws IllegalAccessException if the builder class can't be loaded + * @throws InstantiationException if the builder class can't be loaded */ + @SuppressWarnings("WeakerAccess") protected static EncryptionInfoBuilder getBuilder(EncryptionMode encryptionMode) throws ClassNotFoundException, IllegalAccessException, InstantiationException { ClassLoader cl = EncryptionInfo.class.getClassLoader(); diff --git a/src/java/org/apache/poi/poifs/crypt/Encryptor.java b/src/java/org/apache/poi/poifs/crypt/Encryptor.java index ff954ab6b1..386b8a8747 100644 --- a/src/java/org/apache/poi/poifs/crypt/Encryptor.java +++ b/src/java/org/apache/poi/poifs/crypt/Encryptor.java @@ -26,7 +26,6 @@ import javax.crypto.spec.SecretKeySpec; import org.apache.poi.EncryptedDocumentException; import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; -import org.apache.poi.poifs.filesystem.OPOIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem; public abstract class Encryptor implements Cloneable { @@ -55,9 +54,6 @@ public abstract class Encryptor implements Cloneable { public OutputStream getDataStream(NPOIFSFileSystem fs) throws IOException, GeneralSecurityException { return getDataStream(fs.getRoot()); } - public OutputStream getDataStream(OPOIFSFileSystem fs) throws IOException, GeneralSecurityException { - return getDataStream(fs.getRoot()); - } public OutputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException { return getDataStream(fs.getRoot()); } diff --git a/src/java/org/apache/poi/poifs/crypt/package-info.java b/src/java/org/apache/poi/poifs/crypt/package-info.java new file mode 100644 index 0000000000..924b54ec15 --- /dev/null +++ b/src/java/org/apache/poi/poifs/crypt/package-info.java @@ -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

+ * + * The implementation is split into the following packages:

+ * + *

    + *
  • This package contains common functions for both current implemented cipher modes.
  • + *
  • the {@link org.apache.poi.poifs.crypt.agile agile} package is part of the poi ooxml jar and the provides agile encryption support.
  • + *
  • the {@link org.apache.poi.poifs.crypt.binaryrc4 binaryrc} package is used for the fixed length RC4 encryption of biff/H**F formats
  • + *
  • the {@link org.apache.poi.poifs.crypt.cryptoapi cryptoapi} package is used for the variable length RC encryption of biff/H**F formats
  • + *
  • the {@link org.apache.poi.poifs.crypt.standard standard} package contains classes for the standard encryption ...
  • + *
  • the {@link org.apache.poi.poifs.crypt.xor xor} package contains classes for the xor obfuscation of biff/H**F formats
  • + *
+ * + * @see Apache POI - Encryption support + * @see ECMA-376 Document Encryption + */ +package org.apache.poi.poifs.crypt; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/crypt/package.html b/src/java/org/apache/poi/poifs/crypt/package.html deleted file mode 100644 index 977cf8b5a9..0000000000 --- a/src/java/org/apache/poi/poifs/crypt/package.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - -

Implementation of the ECMA-376 Document Encryption

-

The implementation is split into three packages:

-
    -
  • This package contains common functions for both current implemented cipher modes.
  • -
  • the {@link org.apache.poi.poifs.crypt.standard standard} package is part of the base poi jar and contains classes for the standard encryption ...
  • -
  • the {@link org.apache.poi.poifs.crypt.agile agile} package is part of the poi ooxml jar and the provides agile encryption support.
  • -
- -

Related Documentation

- -Some implementations informations can be found under: - - - -@see org.apache.poi.poifs.crypt.standard -@see org.apache.poi.poifs.crypt.agile - - diff --git a/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java b/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java deleted file mode 100644 index 642ffa0f98..0000000000 --- a/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java +++ /dev/null @@ -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 " + 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()); - } - } - } -} diff --git a/src/java/org/apache/poi/poifs/dev/package-info.java b/src/java/org/apache/poi/poifs/dev/package-info.java new file mode 100644 index 0000000000..4d04219f88 --- /dev/null +++ b/src/java/org/apache/poi/poifs/dev/package-info.java @@ -0,0 +1,26 @@ +/* ==================================================================== + 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. +==================================================================== */ + +/** + * DEV package serves two purposes. + * + *
    + *
  1. Examples for how to use POIFS
  2. + *
  3. tools for developing and validating POIFS
  4. + *
+ */ +package org.apache.poi.poifs.dev; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/dev/package.html b/src/java/org/apache/poi/poifs/dev/package.html deleted file mode 100644 index e4e60cece0..0000000000 --- a/src/java/org/apache/poi/poifs/dev/package.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - -DEV package serves two purposes. 1. Examples for how to use POIFS and 2. tools for developing -and validating POIFS. - -

Related Documentation

- -For overviews, tutorials, examples, guides, and tool documentation, please see: - - - - diff --git a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java index e61039360d..abb90acc26 100644 --- a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java +++ b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java @@ -19,23 +19,19 @@ package org.apache.poi.poifs.eventfilesystem; -import java.io.FileInputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.Iterator; 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.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.PropertyTable; 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; /** @@ -49,62 +45,54 @@ import org.apache.poi.util.IOUtils; public class POIFSReader { - private final POIFSReaderRegistry registry; - private boolean registryClosed; + private final POIFSReaderRegistry registry = new POIFSReaderRegistry(); + private boolean registryClosed = false; private boolean notifyEmptyDirectories; +// private NPOIFSFileSystem poifs; /** - * Create a POIFSReader + * Read from an InputStream and process the documents we get + * + * @param stream the InputStream from which to read the data + * + * @exception IOException on errors reading, or on invalid data */ - public POIFSReader() - { - registry = new POIFSReaderRegistry(); - registryClosed = false; + public void read(final InputStream stream) throws IOException { + try (NPOIFSFileSystem poifs = new NPOIFSFileSystem(stream)) { + read(poifs); + } } /** - * Read from an InputStream and process the documents we get + * Read from a File and process the documents we get * - * @param stream the InputStream from which to read the data + * @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); + } + } - public void read(final InputStream stream) - throws IOException - { + /** + * 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; - // 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 - PropertyTable properties = - new PropertyTable(header_block, data_blocks); + NPropertyTable properties = poifs.getPropertyTable(); // process documents RootProperty root = properties.getRoot(); - processProperties(SmallBlockTableReader - .getSmallDocumentBlocks( - header_block.getBigBlockSize(), - data_blocks, root, - header_block.getSBATStart() - ), - data_blocks, root.getChildren(), new POIFSDocumentPath() - ); + processProperties(poifs, root, new POIFSDocumentPath()); } /** @@ -117,14 +105,11 @@ public class POIFSReader * called */ - public void registerListener(final POIFSReaderListener listener) - { - if (listener == null) - { + public void registerListener(final POIFSReaderListener listener) { + if (listener == null) { throw new NullPointerException(); } - if (registryClosed) - { + if (registryClosed) { throw new IllegalStateException(); } registry.registerListener(listener); @@ -143,9 +128,7 @@ public class POIFSReader * called */ - public void registerListener(final POIFSReaderListener listener, - final String name) - { + public void registerListener(final POIFSReaderListener listener, final String name) { registerListener(listener, null, name); } @@ -166,19 +149,14 @@ public class POIFSReader public void registerListener(final POIFSReaderListener listener, final POIFSDocumentPath path, - final String name) - { - if ((listener == null) || (name == null) || (name.length() == 0)) - { + final String name) { + if ((listener == null) || (name == null) || (name.length() == 0)) { throw new NullPointerException(); } - if (registryClosed) - { + if (registryClosed) { throw new IllegalStateException(); } - registry.registerListener(listener, - (path == null) ? new POIFSDocumentPath() - : path, name); + registry.registerListener(listener, (path == null) ? new POIFSDocumentPath() : path, name); } /** @@ -186,7 +164,7 @@ public class POIFSReader * If this flag is activated, the {@link POIFSReaderListener listener} receives * {@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) { this.notifyEmptyDirectories = notifyEmptyDirectories; @@ -198,139 +176,72 @@ public class POIFSReader * * @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[]) - throws IOException - { - if (args.length == 0) - { + public static void main(String args[]) throws IOException { + if (args.length == 0) { System.err.println("at least one argument required: input filename(s)"); System.exit(1); } // register for all - for (String arg : args) - { - POIFSReader reader = new POIFSReader(); - POIFSReaderListener listener = new SampleListener(); - - reader.registerListener(listener); + for (String arg : args) { + POIFSReader reader = new POIFSReader(); + reader.registerListener(POIFSReader::readEntry); System.out.println("reading " + arg); - FileInputStream istream = new FileInputStream(arg); - reader.read(istream); - istream.close(); + reader.read(new File(arg)); } } - private void processProperties(final BlockList small_blocks, - final BlockList big_blocks, - final Iterator properties, - final POIFSDocumentPath path) - throws IOException { - if (!properties.hasNext() && notifyEmptyDirectories) { - Iterator listeners = registry.getListeners(path, "."); - while (listeners.hasNext()) { - POIFSReaderListener pl = listeners.next(); - POIFSReaderEvent pe = new POIFSReaderEvent(null, path, null); - pl.processPOIFSReaderEvent(pe); + private static void readEntry(POIFSReaderEvent event) { + POIFSDocumentPath path = event.getPath(); + StringBuilder sb = new StringBuilder(); + + try (DocumentInputStream istream = event.getStream()) { + sb.setLength(0); + int pathLength = path.length(); + for (int k = 0; k < pathLength; k++) { + sb.append("/").append(path.getComponent(k)); } - return; + byte[] data = IOUtils.toByteArray(istream); + sb.append("/").append(event.getName()).append(": ").append(data.length).append(" bytes read"); + System.out.println(sb); + } catch (IOException ignored) { } + } - while (properties.hasNext()) - { - Property property = properties.next(); - String name = property.getName(); + 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()) { POIFSDocumentPath new_path = new POIFSDocumentPath(path,new String[]{name}); - DirectoryProperty dp = (DirectoryProperty) property; - processProperties(small_blocks, big_blocks, dp.getChildren(), new_path); + processProperties(poifs, (DirectoryProperty) property, new_path); } else { - int startBlock = property.getStartBlock(); - Iterator listeners = registry.getListeners(path, name); - - if (listeners.hasNext()) - { - int size = property.getSize(); - OPOIFSDocument document = null; - - if (property.shouldUseSmallBlocks()) - { - document = - new OPOIFSDocument(name, small_blocks - .fetchBlocks(startBlock, -1), size); - } - else - { - document = - 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); + NPOIFSDocument document = null; + for (POIFSReaderListener rl : registry.getListeners(path, name)) { + if (document == null) { + document = new NPOIFSDocument((DocumentProperty)property, poifs); } - else - { - big_blocks.fetchBlocks(startBlock, -1); + try (DocumentInputStream dis = new DocumentInputStream(document)) { + POIFSReaderEvent pe = new POIFSReaderEvent(dis, path, name); + rl.processPOIFSReaderEvent(pe); } } } } - } - - private static class SampleListener - implements POIFSReaderListener - { - - /** - * Constructor SampleListener - */ - SampleListener() - { + if (hasChildren || !notifyEmptyDirectories) { + return; } - /** - * Method processPOIFSReaderEvent - * - * @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); - } + for (POIFSReaderListener rl : registry.getListeners(path, ".")) { + POIFSReaderEvent pe = new POIFSReaderEvent(null, path, null); + rl.processPOIFSReaderEvent(pe); } } } diff --git a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderRegistry.java b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderRegistry.java index 0a6c29bd9f..9ffac63120 100644 --- a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderRegistry.java +++ b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReaderRegistry.java @@ -79,34 +79,21 @@ class POIFSReaderRegistry // not an omnivorous listener (if it was, this method is a // no-op) - Set descriptors = selectiveListeners.get(listener); + Set 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 - descriptors = new HashSet<>(); - selectiveListeners.put(listener, descriptors); - } - DocumentDescriptor descriptor = new DocumentDescriptor(path, - documentName); - - if (descriptors.add(descriptor)) - { + if (descriptors.add(descriptor)) { // this listener wasn't already listening for this // document -- add the listener to the set of // listeners for this document Set listeners = - chosenDocumentDescriptors.get(descriptor); - - if (listeners == null) - { + chosenDocumentDescriptors.computeIfAbsent(descriptor, k -> new HashSet<>()); - // nobody was listening for this document before - listeners = new HashSet<>(); - chosenDocumentDescriptors.put(descriptor, listeners); - } + // nobody was listening for this document before listeners.add(listener); } } @@ -141,7 +128,7 @@ class POIFSReaderRegistry * @return an Iterator POIFSReaderListeners; may be empty */ - Iterator getListeners(final POIFSDocumentPath path, final String name) + Iterable getListeners(final POIFSDocumentPath path, final String name) { Set rval = new HashSet<>(omnivorousListeners); Set selectiveListenersInner = @@ -151,20 +138,16 @@ class POIFSReaderRegistry { rval.addAll(selectiveListenersInner); } - return rval.iterator(); + return rval; } private void removeSelectiveListener(final POIFSReaderListener listener) { Set selectedDescriptors = selectiveListeners.remove(listener); - if (selectedDescriptors != null) - { - Iterator iter = selectedDescriptors.iterator(); - - while (iter.hasNext()) - { - dropDocument(listener, iter.next()); + if (selectedDescriptors != null) { + for (DocumentDescriptor selectedDescriptor : selectedDescriptors) { + dropDocument(listener, selectedDescriptor); } } } diff --git a/src/java/org/apache/poi/poifs/eventfilesystem/package-info.java b/src/java/org/apache/poi/poifs/eventfilesystem/package-info.java new file mode 100644 index 0000000000..34760da4d4 --- /dev/null +++ b/src/java/org/apache/poi/poifs/eventfilesystem/package-info.java @@ -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. +==================================================================== */ + +/** + * The eventfilesystem is an efficient method for reading OLE 2 CDF files. It is to OLE 2 CDF what SAX is to XML. + * + * @see org.apache.poi.poifs.filesystem + */ +package org.apache.poi.poifs.eventfilesystem; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/eventfilesystem/package.html b/src/java/org/apache/poi/poifs/eventfilesystem/package.html deleted file mode 100644 index 472a0d93ef..0000000000 --- a/src/java/org/apache/poi/poifs/eventfilesystem/package.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - -The eventfilesystem is an efficient method for reading OLE 2 CDF files. It is to OLE 2 CDF what SAX is to XML. - -

Related Documentation

- -For overviews, tutorials, examples, guides, and tool documentation, please see: - - - -@see org.apache.poi.poifs.filesystem - - diff --git a/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java b/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java index dfeb7d2c03..b6af88babe 100644 --- a/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java +++ b/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java @@ -44,33 +44,16 @@ public class DirectoryNode { // Map of Entry instances, keyed by their names - private Map _byname; + private final Map _byname = new HashMap<>(); + // Our list of entries, kept sorted to preserve order - private ArrayList _entries; + private final ArrayList _entries = new ArrayList<>(); - // Only one of these two will exist - // the OPOIFSFileSystem we belong to - private OPOIFSFileSystem _ofilesystem; // the NPOIFSFileSytem we belong to - private NPOIFSFileSystem _nfilesystem; + private final NPOIFSFileSystem _nfilesystem; // the path described by this document - private 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); - } + private final POIFSDocumentPath _path; /** * create a DirectoryNode. This method is not public by design; it @@ -83,17 +66,8 @@ public class DirectoryNode DirectoryNode(final DirectoryProperty property, final NPOIFSFileSystem nfilesystem, 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); - this._ofilesystem = ofilesystem; this._nfilesystem = nfilesystem; if (parent == null) @@ -103,12 +77,10 @@ public class DirectoryNode else { _path = new POIFSDocumentPath(parent._path, new String[] - { - property.getName() - }); + { + property.getName() + }); } - _byname = new HashMap<>(); - _entries = new ArrayList<>(); Iterator iter = property.getChildren(); while (iter.hasNext()) @@ -119,11 +91,7 @@ public class DirectoryNode if (child.isDirectory()) { DirectoryProperty childDir = (DirectoryProperty) child; - if(_ofilesystem != null) { - childNode = new DirectoryNode(childDir, _ofilesystem, this); - } else { - childNode = new DirectoryNode(childDir, _nfilesystem, this); - } + childNode = new DirectoryNode(childDir, _nfilesystem, this); } else { @@ -151,15 +119,6 @@ public class DirectoryNode 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 @@ -218,30 +177,7 @@ public class DirectoryNode * * @return the new DocumentEntry * - * @exception IOException - */ - 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 + * @exception IOException if the document can't be created */ DocumentEntry createDocument(final NPOIFSDocument document) throws IOException @@ -302,14 +238,11 @@ public class DirectoryNode _entries.remove(entry); _byname.remove(entry.getName()); - if(_ofilesystem != null) { - _ofilesystem.remove(entry); - } else { - try { - _nfilesystem.remove(entry); - } catch (IOException e) { - // TODO Work out how to report this, given we can't change the method signature... - } + try { + _nfilesystem.remove(entry); + } catch (IOException e) { + // TODO Work out how to report this, given we can't change the method signature... + throw new RuntimeException(e); } } return rval; @@ -411,18 +344,14 @@ public class DirectoryNode * * @return the new DocumentEntry * - * @exception IOException + * @exception IOException if the document can't be created */ public DocumentEntry createDocument(final String name, final InputStream stream) throws IOException { - if(_nfilesystem != null) { - return createDocument(new NPOIFSDocument(name, _nfilesystem, stream)); - } else { - return createDocument(new OPOIFSDocument(name, stream)); - } + return createDocument(new NPOIFSDocument(name, _nfilesystem, stream)); } /** @@ -434,18 +363,14 @@ public class DirectoryNode * * @return the new DocumentEntry * - * @exception IOException + * @exception IOException if the document can't be created */ public DocumentEntry createDocument(final String name, final int size, final POIFSWriterListener writer) throws IOException { - if(_nfilesystem != null) { - return createDocument(new NPOIFSDocument(name, size, _nfilesystem, writer)); - } else { - return createDocument(new OPOIFSDocument(name, size, _path, writer)); - } + return createDocument(new NPOIFSDocument(name, size, _nfilesystem, writer)); } /** @@ -455,22 +380,16 @@ public class DirectoryNode * * @return the new DirectoryEntry * - * @exception IOException + * @exception IOException if the directory can't be created */ public DirectoryEntry createDirectory(final String name) throws IOException { - DirectoryNode rval; DirectoryProperty property = new DirectoryProperty(name); - if(_ofilesystem != null) { - rval = new DirectoryNode(property, _ofilesystem, this); - _ofilesystem.addDirectory(property); - } else { - rval = new DirectoryNode(property, _nfilesystem, this); - _nfilesystem.addDirectory(property); - } + DirectoryNode rval = new DirectoryNode(property, _nfilesystem, this); + _nfilesystem.addDirectory(property); (( DirectoryProperty ) getProperty()).addChild(property); _entries.add(rval); @@ -487,9 +406,9 @@ public class DirectoryNode * * @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, final InputStream stream) throws IOException @@ -498,15 +417,9 @@ public class DirectoryNode return createDocument(name, stream); } else { DocumentNode existing = (DocumentNode)getEntry(name); - if (_nfilesystem != null) { - NPOIFSDocument nDoc = new NPOIFSDocument(existing); - nDoc.replaceContents(stream); - return existing; - } else { - // Do it the hard way for Old POIFS... - deleteEntry(existing); - return createDocument(name, stream); - } + NPOIFSDocument nDoc = new NPOIFSDocument(existing); + nDoc.replaceContents(stream); + return existing; } } diff --git a/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java b/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java index 314cae0ee2..3aeaa19320 100644 --- a/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java +++ b/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java @@ -20,7 +20,6 @@ package org.apache.poi.poifs.filesystem; import java.io.IOException; import java.io.InputStream; -import org.apache.poi.util.IOUtils; import org.apache.poi.util.LittleEndianInput; 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 */ 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; /** For use by downstream implementations */ @@ -55,27 +50,7 @@ public class DocumentInputStream extends InputStream implements LittleEndianInpu if (!(document instanceof DocumentNode)) { throw new IOException("Cannot open internal document storage"); } - DocumentNode documentNode = (DocumentNode)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); + delegate = new NDocumentInputStream(document); } /** diff --git a/src/java/org/apache/poi/poifs/filesystem/DocumentNode.java b/src/java/org/apache/poi/poifs/filesystem/DocumentNode.java index 19143fd745..f60c1dc5da 100644 --- a/src/java/org/apache/poi/poifs/filesystem/DocumentNode.java +++ b/src/java/org/apache/poi/poifs/filesystem/DocumentNode.java @@ -35,7 +35,7 @@ public class DocumentNode { // underlying POIFSDocument instance - private OPOIFSDocument _document; + private NPOIFSDocument _document; /** * create a DocumentNode. This method is not public by design; it @@ -56,7 +56,7 @@ public class DocumentNode * * @return the internal POIFSDocument */ - OPOIFSDocument getDocument() + NPOIFSDocument getDocument() { return _document; } diff --git a/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java b/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java index e2ba3dc3bd..1fdf2e4770 100644 --- a/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java +++ b/src/java/org/apache/poi/poifs/filesystem/EntryUtils.java @@ -16,27 +16,31 @@ ==================================================================== */ package org.apache.poi.poifs.filesystem; -import java.io.FileNotFoundException; +import java.io.EOFException; import java.io.IOException; -import java.util.HashMap; import java.util.Iterator; import java.util.List; 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; @Internal -public class EntryUtils -{ +public final class EntryUtils { + private EntryUtils() {} /** * Copies an Entry into a target POIFS directory, recursively */ @Internal public static void copyNodeRecursively( Entry entry, DirectoryEntry target ) - throws IOException { - // logger.log( POILogger.ERROR, "copyNodeRecursively called with "+entry.getName()+ - // ","+target.getName()); + throws IOException { if ( entry.isDirectoryEntry() ) { DirectoryEntry dirEntry = (DirectoryEntry)entry; DirectoryEntry newTarget = target.createDirectory( entry.getName() ); @@ -62,8 +66,8 @@ public class EntryUtils * @param targetRoot * is the target Directory to copy to */ - public static void copyNodes(DirectoryEntry sourceRoot, - DirectoryEntry targetRoot) throws IOException { + public static void copyNodes(DirectoryEntry sourceRoot, DirectoryEntry targetRoot) + throws IOException { for (Entry entry : sourceRoot) { copyNodeRecursively( entry, targetRoot ); } @@ -77,22 +81,8 @@ public class EntryUtils * @param target * is the target POIFS to copy to */ - public static void copyNodes( OPOIFSFileSystem source, - OPOIFSFileSystem target ) 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 - { + public static void copyNodes( NPOIFSFileSystem source, NPOIFSFileSystem target ) + throws IOException { copyNodes( source.getRoot(), target.getRoot() ); } @@ -106,27 +96,8 @@ public class EntryUtils * @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( OPOIFSFileSystem source, - OPOIFSFileSystem target, List excepts ) 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 excepts ) throws IOException - { + public static void copyNodes( NPOIFSFileSystem source, NPOIFSFileSystem target, List excepts ) + throws IOException { copyNodes( new FilteringDirectoryNode(source.getRoot(), excepts), new FilteringDirectoryNode(target.getRoot(), excepts) @@ -142,114 +113,137 @@ public class EntryUtils * use a {@link FilteringDirectoryNode} */ public static boolean areDirectoriesIdentical(DirectoryEntry dirA, DirectoryEntry dirB) { - // First, check names - 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 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; + return new DirectoryDelegate(dirA).equals(new DirectoryDelegate(dirB)); } /** - * Checks to see if two Documents have the same name - * and the same contents. (Their parent directories are - * not checked) + * 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.

+ * + * (Their parent directories are not checked) */ - public static boolean areDocumentsIdentical(DocumentEntry docA, DocumentEntry docB) throws IOException { - if (! docA.getName().equals(docB.getName())) { - // Names don't match, not the same - return false; - } - if (docA.getSize() != docB.getSize()) { - // Wrong sizes, can't have the same contents - return false; - } - - boolean matches = true; - DocumentInputStream inpA = null, inpB = null; - try { - inpA = new DocumentInputStream(docA); - inpB = new DocumentInputStream(docB); - - int readA, readB; - do { - readA = inpA.read(); - readB = inpB.read(); - if (readA != readB) { - matches = false; - break; - } - } while(readA != -1 && readB != -1); - } finally { - if (inpA != null) inpA.close(); - if (inpB != null) inpB.close(); - } - - return matches; + @SuppressWarnings("WeakerAccess") + public static boolean areDocumentsIdentical(DocumentEntry docA, DocumentEntry docB) + throws IOException { + try { + return new DocumentDelegate(docA).equals(new DocumentDelegate(docB)); + } catch (RuntimeException e) { + if (e.getCause() instanceof IOException) { + throw (IOException)e.getCause(); + } else { + throw e; + } + } + } + + private interface POIDelegate { + } + + private static class DirectoryDelegate implements POIDelegate { + final DirectoryEntry dir; + + DirectoryDelegate(DirectoryEntry dir) { + this.dir = dir; + } + + private Map entries() { + return StreamSupport.stream(dir.spliterator(), false) + .collect(Collectors.toMap(Entry::getName, DirectoryDelegate::toDelegate)); + } + + private static POIDelegate toDelegate(Entry entry) { + return (entry.isDirectoryEntry()) + ? new DirectoryDelegate((DirectoryEntry)entry) + : new DocumentDelegate((DocumentEntry)entry); + } + + @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= 0) : "Document size can't be < 0"; + DocumentNode doc = (DocumentNode)document; DocumentProperty property = (DocumentProperty)doc.getProperty(); _document = new NPOIFSDocument( @@ -284,33 +288,33 @@ public final class NDocumentInputStream extends DocumentInputStream { @Override public long readLong() { - checkAvaliable(SIZE_LONG); - byte[] data = new byte[SIZE_LONG]; - readFully(data, 0, SIZE_LONG); + checkAvaliable(LONG_SIZE); + byte[] data = new byte[LONG_SIZE]; + readFully(data, 0, LONG_SIZE); return LittleEndian.getLong(data, 0); } @Override public short readShort() { - checkAvaliable(SIZE_SHORT); - byte[] data = new byte[SIZE_SHORT]; - readFully(data, 0, SIZE_SHORT); + checkAvaliable(SHORT_SIZE); + byte[] data = new byte[SHORT_SIZE]; + readFully(data, 0, SHORT_SIZE); return LittleEndian.getShort(data); } @Override public int readInt() { - checkAvaliable(SIZE_INT); - byte[] data = new byte[SIZE_INT]; - readFully(data, 0, SIZE_INT); + checkAvaliable(INT_SIZE); + byte[] data = new byte[INT_SIZE]; + readFully(data, 0, INT_SIZE); return LittleEndian.getInt(data); } @Override public int readUShort() { - checkAvaliable(SIZE_SHORT); - byte[] data = new byte[SIZE_SHORT]; - readFully(data, 0, SIZE_SHORT); + checkAvaliable(SHORT_SIZE); + byte[] data = new byte[SHORT_SIZE]; + readFully(data, 0, SHORT_SIZE); return LittleEndian.getUShort(data); } diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java index 22e4106962..f25838b570 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java @@ -17,6 +17,8 @@ package org.apache.poi.poifs.filesystem; +import static java.util.Collections.emptyList; + import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -25,7 +27,6 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; -import java.util.List; import org.apache.poi.poifs.common.POIFSConstants; 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 is the {@link NPOIFSFileSystem} version. */ -public final class NPOIFSDocument implements POIFSViewable { +public final class NPOIFSDocument implements POIFSViewable, Iterable { //arbitrarily selected; may need to increase private static final int MAX_RECORD_LENGTH = 100_000; @@ -51,7 +52,7 @@ public final class NPOIFSDocument implements POIFSViewable { /** * Constructor for an existing Document */ - public NPOIFSDocument(DocumentNode document) throws IOException { + public NPOIFSDocument(DocumentNode document) { this((DocumentProperty)document.getProperty(), ((DirectoryNode)document.getParent()).getNFileSystem()); } @@ -59,9 +60,7 @@ public final class NPOIFSDocument implements POIFSViewable { /** * Constructor for an existing Document */ - public NPOIFSDocument(DocumentProperty property, NPOIFSFileSystem filesystem) - throws IOException - { + public NPOIFSDocument(DocumentProperty property, NPOIFSFileSystem filesystem) { this._property = property; this._filesystem = filesystem; @@ -90,7 +89,8 @@ public final class NPOIFSDocument implements POIFSViewable { // Build the property for it 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) @@ -116,7 +116,8 @@ public final class NPOIFSDocument implements POIFSViewable { // And build the property for it 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); // 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()); _block_size = _filesystem.getMiniStore().getBlockStoreBlockSize(); } else { @@ -140,26 +142,21 @@ public final class NPOIFSDocument implements POIFSViewable { bis.reset(); // Store it - OutputStream os = _stream.getOutputStream(); - byte buf[] = new byte[1024]; - int length = 0; - - for (int readBytes; (readBytes = bis.read(buf)) != -1; length += readBytes) { - os.write(buf, 0, readBytes); - } - - // Pad to the end of the block with -1s - 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); + final long length; + try (OutputStream os = _stream.getOutputStream()) { + length = IOUtils.copy(bis, os); + + // Pad to the end of the block with -1s + 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); + } } - - // Tidy and return the length - os.close(); - return length; + + return (int)length; } /** @@ -178,15 +175,15 @@ public final class NPOIFSDocument implements POIFSViewable { int getDocumentBlockSize() { return _block_size; } - - Iterator getBlockIterator() { - if(getSize() > 0) { - return _stream.getBlockIterator(); - } else { - List empty = Collections.emptyList(); - return empty.iterator(); - } - } + + @Override + public Iterator iterator() { + return getBlockIterator(); + } + + Iterator getBlockIterator() { + return (getSize() > 0 ? _stream : Collections.emptyList()).iterator(); + } /** * @return size of the document @@ -240,7 +237,7 @@ public final class NPOIFSDocument implements POIFSViewable { * store */ public Iterator getViewableIterator() { - return Collections.emptyList().iterator(); + return emptyList().iterator(); } /** @@ -261,10 +258,7 @@ public final class NPOIFSDocument implements POIFSViewable { * @return short description */ public String getShortDescription() { - StringBuffer buffer = new StringBuffer(); - buffer.append("Document: \"").append(_property.getName()).append("\""); - buffer.append(" size = ").append(getSize()); - return buffer.toString(); + return "Document: \"" + _property.getName() + "\" size = " + getSize(); } } diff --git a/src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java b/src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java deleted file mode 100644 index 944e3f322f..0000000000 --- a/src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java +++ /dev/null @@ -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 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 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; - } -} diff --git a/src/java/org/apache/poi/poifs/filesystem/OPOIFSDocument.java b/src/java/org/apache/poi/poifs/filesystem/OPOIFSDocument.java deleted file mode 100644 index 43820ab532..0000000000 --- a/src/java/org/apache/poi/poifs/filesystem/OPOIFSDocument.java +++ /dev/null @@ -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 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 null if offset 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 = ""; - - 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 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 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 true 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 true 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 -} diff --git a/src/java/org/apache/poi/poifs/filesystem/OPOIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/OPOIFSFileSystem.java deleted file mode 100644 index 18bc8be0bb..0000000000 --- a/src/java/org/apache/poi/poifs/filesystem/OPOIFSFileSystem.java +++ /dev/null @@ -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; - -/** - *

This is the main class of the POIFS system; it manages the entire - * life cycle of the filesystem.

- *

This is the older version, which uses more memory, and doesn't - * support in-place writes.

- */ -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 _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 InputStream. Normally the stream is read until - * EOF. The stream is always closed.

- * - * Some streams are usable after reaching EOF (typically those that return true - * for markSupported()). In the unlikely case that the caller has such a stream - * and needs to use it after this constructor completes, a work around is to wrap the - * stream in order to trap the close() call. A convenience method ( - * createNonClosingInputStream()) has been provided for this purpose: - *

-     * InputStream wrappedStream = OPOIFSFileSystem.createNonClosingInputStream(is);
-     * HSSFWorkbook wb = new HSSFWorkbook(wrappedStream);
-     * is.reset();
-     * doSomethingElse(is);
-     * 
- * Note also the special case of ByteArrayInputStream for which the close() - * method does nothing. - *
-     * ByteArrayInputStream bais = ...
-     * HSSFWorkbook wb = new HSSFWorkbook(bais); // calls bais.close() !
-     * bais.reset(); // no problem
-     * doSomethingElse(bais);
-     * 
- * - * @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 false 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 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 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 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 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 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 - diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java index a12a9369d8..39065c24a2 100644 --- a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java +++ b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java @@ -141,6 +141,6 @@ public class POIFSFileSystem * arg[ 1 ] is the output file */ public static void main(String args[]) throws IOException { - OPOIFSFileSystem.main(args); + NPOIFSFileSystem.main(args); } } diff --git a/src/java/org/apache/poi/poifs/filesystem/package-info.java b/src/java/org/apache/poi/poifs/filesystem/package-info.java new file mode 100644 index 0000000000..84c2d9f35d --- /dev/null +++ b/src/java/org/apache/poi/poifs/filesystem/package-info.java @@ -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. +==================================================================== */ + +/** + * filesystem package maps OLE 2 Compound document files to a more familiar filesystem interface. + * + * @see org.apache.poi.poifs.eventfilesystem + */ +package org.apache.poi.poifs.filesystem; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/filesystem/package.html b/src/java/org/apache/poi/poifs/filesystem/package.html deleted file mode 100644 index d673ed5934..0000000000 --- a/src/java/org/apache/poi/poifs/filesystem/package.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - -filesystem package maps OLE 2 Compound document files to a more familiar filesystem interface. - -

Related Documentation

- -For overviews, tutorials, examples, guides, and tool documentation, please see: - - - -@see org.apache.poi.poifs.eventfilesystem - - diff --git a/src/java/org/apache/poi/poifs/package-info.java b/src/java/org/apache/poi/poifs/package-info.java new file mode 100644 index 0000000000..78420021c9 --- /dev/null +++ b/src/java/org/apache/poi/poifs/package-info.java @@ -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; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/package.html b/src/java/org/apache/poi/poifs/package.html deleted file mode 100644 index f86821c8a8..0000000000 --- a/src/java/org/apache/poi/poifs/package.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - -Poor Obfuscation Implementation FileSystem APIs implement the OLE 2 Compound Document format in -pure Java. All POI subprojects are based upon this API. - -

Related Documentation

- -For overviews, tutorials, examples, guides, and tool documentation, please see: - - - -@see org.apache.poi.hssf -@see org.apache.poi.hpsf - - diff --git a/src/java/org/apache/poi/poifs/property/DirectoryProperty.java b/src/java/org/apache/poi/poifs/property/DirectoryProperty.java index 12d0cc855d..07846736c2 100644 --- a/src/java/org/apache/poi/poifs/property/DirectoryProperty.java +++ b/src/java/org/apache/poi/poifs/property/DirectoryProperty.java @@ -30,7 +30,7 @@ import java.util.Set; /** * Directory property */ -public class DirectoryProperty extends Property implements Parent, Iterable { // TODO - fix instantiable superclass +public class DirectoryProperty extends Property implements Parent, Iterable { /** List of Property instances */ private List _children; diff --git a/src/java/org/apache/poi/poifs/property/DocumentProperty.java b/src/java/org/apache/poi/poifs/property/DocumentProperty.java index ea693d8871..38d196975e 100644 --- a/src/java/org/apache/poi/poifs/property/DocumentProperty.java +++ b/src/java/org/apache/poi/poifs/property/DocumentProperty.java @@ -19,14 +19,14 @@ 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 */ public class DocumentProperty extends Property { // the POIFSDocument this property is associated with - private OPOIFSDocument _document; + private NPOIFSDocument _document; /** * Constructor @@ -64,7 +64,7 @@ public class DocumentProperty extends Property { * * @param doc the associated POIFSDocument */ - public void setDocument(OPOIFSDocument doc) + public void setDocument(NPOIFSDocument doc) { _document = doc; } @@ -74,7 +74,7 @@ public class DocumentProperty extends Property { * * @return the associated document */ - public OPOIFSDocument getDocument() + public NPOIFSDocument getDocument() { return _document; } diff --git a/src/java/org/apache/poi/poifs/property/RootProperty.java b/src/java/org/apache/poi/poifs/property/RootProperty.java index 5a8f3d52ef..3cb4a6e43b 100644 --- a/src/java/org/apache/poi/poifs/property/RootProperty.java +++ b/src/java/org/apache/poi/poifs/property/RootProperty.java @@ -18,7 +18,6 @@ package org.apache.poi.poifs.property; import org.apache.poi.poifs.common.POIFSConstants; -import org.apache.poi.poifs.storage.SmallDocumentBlock; /** * Root property @@ -43,9 +42,7 @@ public final class RootProperty extends DirectoryProperty { * @param array byte data * @param offset offset into byte data */ - protected RootProperty(final int index, final byte [] array, - final int offset) - { + RootProperty(final int index, final byte [] array, final int offset) { super(index, array, offset); } @@ -56,7 +53,9 @@ public final class RootProperty extends DirectoryProperty { */ 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); } /** diff --git a/src/java/org/apache/poi/poifs/property/package-info.java b/src/java/org/apache/poi/poifs/property/package-info.java new file mode 100644 index 0000000000..9ffa4aebc7 --- /dev/null +++ b/src/java/org/apache/poi/poifs/property/package-info.java @@ -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; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/property/package.html b/src/java/org/apache/poi/poifs/property/package.html deleted file mode 100644 index ff11a205aa..0000000000 --- a/src/java/org/apache/poi/poifs/property/package.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - -property package contains high and low level Property structures for POIFS. - -

Related Documentation

- -For overviews, tutorials, examples, guides, and tool documentation, please see: - - - -@see org.apache.poi.poifs.filesystem - - diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java b/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java index 27e4b41e87..5470bde5b8 100644 --- a/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java +++ b/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java @@ -27,9 +27,9 @@ import org.apache.poi.util.LittleEndianConsts; */ public interface HeaderBlockConstants { - public static final long _signature = 0xE11AB1A1E011CFD0L; - public static final int _bat_array_offset = 0x4c; - public static final int _max_bats_in_header = + long _signature = 0xE11AB1A1E011CFD0L; + int _bat_array_offset = 0x4c; + int _max_bats_in_header = (POIFSConstants.SMALLER_BIG_BLOCK_SIZE - _bat_array_offset) / LittleEndianConsts.INT_SIZE; // If 4k blocks, rest is blank @@ -39,12 +39,12 @@ public interface HeaderBlockConstants // XBAT ~= DIFat // useful offsets - public static final int _signature_offset = 0; - public static final int _bat_count_offset = 0x2C; - public static final int _property_start_offset = 0x30; - public static final int _sbat_start_offset = 0x3C; - public static final int _sbat_block_count_offset = 0x40; - public static final int _xbat_start_offset = 0x44; - public static final int _xbat_count_offset = 0x48; -} // end public interface HeaderBlockConstants + int _signature_offset = 0; + int _bat_count_offset = 0x2C; + int _property_start_offset = 0x30; + int _sbat_start_offset = 0x3C; + int _sbat_block_count_offset = 0x40; + int _xbat_start_offset = 0x44; + int _xbat_count_offset = 0x48; +} diff --git a/src/java/org/apache/poi/poifs/storage/SmallBlockTableReader.java b/src/java/org/apache/poi/poifs/storage/SmallBlockTableReader.java deleted file mode 100644 index 605b749af6..0000000000 --- a/src/java/org/apache/poi/poifs/storage/SmallBlockTableReader.java +++ /dev/null @@ -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; - } -} diff --git a/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java b/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java deleted file mode 100644 index 3d2b16fe5b..0000000000 --- a/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java +++ /dev/null @@ -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 _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 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 ********** */ -} diff --git a/src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java b/src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java deleted file mode 100644 index 711a2d56a3..0000000000 --- a/src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java +++ /dev/null @@ -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 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 extract(POIFSBigBlockSize bigBlockSize, ListManagedBlock [] blocks) - throws IOException - { - int _blocks_per_big_block = getBlocksPerBigBlock(bigBlockSize); - - List 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; - } -} diff --git a/src/java/org/apache/poi/poifs/storage/SmallDocumentBlockList.java b/src/java/org/apache/poi/poifs/storage/SmallDocumentBlockList.java deleted file mode 100644 index cc6bb7c17f..0000000000 --- a/src/java/org/apache/poi/poifs/storage/SmallDocumentBlockList.java +++ /dev/null @@ -1,41 +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.util.*; - -/** - * A list of SmallDocumentBlocks instances, and methods to manage the list - */ -public class SmallDocumentBlockList - extends BlockListImpl -{ - /** - * Constructor SmallDocumentBlockList - * - * @param blocks a list of SmallDocumentBlock instances - */ - - public SmallDocumentBlockList(final List blocks) - { - setBlocks(blocks.toArray(new SmallDocumentBlock[blocks.size()])); - } -} - diff --git a/src/java/org/apache/poi/poifs/storage/package-info.java b/src/java/org/apache/poi/poifs/storage/package-info.java new file mode 100644 index 0000000000..9fadf9df91 --- /dev/null +++ b/src/java/org/apache/poi/poifs/storage/package-info.java @@ -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; \ No newline at end of file diff --git a/src/java/org/apache/poi/poifs/storage/package.html b/src/java/org/apache/poi/poifs/storage/package.html deleted file mode 100644 index b098350c27..0000000000 --- a/src/java/org/apache/poi/poifs/storage/package.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - -storage package contains low level binary structures for POIFS's implementation of the OLE 2 -Compound Document Format. - -

Related Documentation

- -For overviews, tutorials, examples, guides, and tool documentation, please see: - - - - diff --git a/src/java/org/apache/poi/util/LittleEndianOutputStream.java b/src/java/org/apache/poi/util/LittleEndianOutputStream.java index fa4f9d1abe..920ff40519 100644 --- a/src/java/org/apache/poi/util/LittleEndianOutputStream.java +++ b/src/java/org/apache/poi/util/LittleEndianOutputStream.java @@ -21,10 +21,6 @@ import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; -/** - * - * @author Josh Micich - */ public final class LittleEndianOutputStream extends FilterOutputStream implements LittleEndianOutput { public LittleEndianOutputStream(OutputStream out) { super(out); @@ -49,7 +45,7 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement int b3 = (v >>> 24) & 0xFF; int b2 = (v >>> 16) & 0xFF; int b1 = (v >>> 8) & 0xFF; - int b0 = (v/* >>> 0*/) & 0xFF; + int b0 = (v) & 0xFF; try { out.write(b0); out.write(b1); @@ -69,7 +65,7 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement @Override public void writeShort(int v) { int b1 = (v >>> 8) & 0xFF; - int b0 = (v/* >>> 0*/) & 0xFF; + int b0 = (v) & 0xFF; try { out.write(b0); out.write(b1); @@ -95,4 +91,37 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement 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); + } + } } diff --git a/src/ooxml/java/org/apache/poi/ooxml/extractor/ExtractorFactory.java b/src/ooxml/java/org/apache/poi/ooxml/extractor/ExtractorFactory.java index c718b2295d..50885f1ab1 100644 --- a/src/ooxml/java/org/apache/poi/ooxml/extractor/ExtractorFactory.java +++ b/src/ooxml/java/org/apache/poi/ooxml/extractor/ExtractorFactory.java @@ -48,7 +48,6 @@ import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; 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.POIFSFileSystem; import org.apache.poi.sl.extractor.SlideShowExtractor; @@ -79,12 +78,15 @@ import org.apache.xmlbeans.XmlException; * off switching to Apache Tika instead!

*/ @SuppressWarnings("WeakerAccess") -public class ExtractorFactory { +public final class ExtractorFactory { private static final POILogger logger = POILogFactory.getLogger(ExtractorFactory.class); public static final String CORE_DOCUMENT_REL = PackageRelationshipTypes.CORE_DOCUMENT; - protected 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 VISIO_DOCUMENT_REL = PackageRelationshipTypes.VISIO_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? @@ -128,6 +130,7 @@ public class ExtractorFactory { return OLE2ExtractorFactory.getPreferEventExtractor(); } + @SuppressWarnings("unchecked") public static T createExtractor(File f) throws IOException, OpenXML4JException, XmlException { NPOIFSFileSystem fs = null; try { @@ -230,13 +233,13 @@ public class ExtractorFactory { // Is it XSLF? for (XSLFRelation rel : XSLFPowerPointExtractor.SUPPORTED_TYPES) { if ( rel.getContentType().equals( contentType ) ) { - return new SlideShowExtractor(new XMLSlideShow(pkg)); + return new SlideShowExtractor<>(new XMLSlideShow(pkg)); } } // special handling for SlideShow-Theme-files, if (XSLFRelation.THEME_MANAGER.getContentType().equals(contentType)) { - return new SlideShowExtractor(new XMLSlideShow(pkg)); + return new SlideShowExtractor<>(new XMLSlideShow(pkg)); } // How about xlsb? @@ -262,10 +265,8 @@ public class ExtractorFactory { public static T createExtractor(NPOIFSFileSystem fs) throws IOException, OpenXML4JException, XmlException { return createExtractor(fs.getRoot()); } - public static T createExtractor(OPOIFSFileSystem fs) throws IOException, OpenXML4JException, XmlException { - return createExtractor(fs.getRoot()); - } + @SuppressWarnings("unchecked") public static T createExtractor(DirectoryNode poifsDir) throws IOException, OpenXML4JException, XmlException { // First, check for OOXML @@ -374,7 +375,7 @@ public class ExtractorFactory { throw new IOException(e.getMessage(), e); } } - return textExtractors.toArray(new POITextExtractor[textExtractors.size()]); + return textExtractors.toArray(new POITextExtractor[0]); } /** diff --git a/src/ooxml/testcases/org/apache/poi/extractor/ooxml/TestExtractorFactory.java b/src/ooxml/testcases/org/apache/poi/extractor/ooxml/TestExtractorFactory.java index be58e3d699..46681f71e1 100644 --- a/src/ooxml/testcases/org/apache/poi/extractor/ooxml/TestExtractorFactory.java +++ b/src/ooxml/testcases/org/apache/poi/extractor/ooxml/TestExtractorFactory.java @@ -30,10 +30,9 @@ import java.io.IOException; import java.util.Locale; import org.apache.poi.POIDataSamples; +import org.apache.poi.UnsupportedFileFormatException; import org.apache.poi.extractor.POIOLE2TextExtractor; 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.hpbf.extractor.PublisherTextExtractor; 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.WordExtractor; 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.opc.OPCPackage; 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.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.xssf.extractor.XSSFBEventBasedExcelExtractor; import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor; @@ -65,11 +62,10 @@ import org.junit.Test; */ public class TestExtractorFactory { - private static final POILogger LOG = POILogFactory.getLogger(TestExtractorFactory.class); - private static final POIDataSamples ssTests = POIDataSamples.getSpreadSheetInstance(); private static final File xls = getFileAndCheck(ssTests, "SampleSS.xls"); 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 xltx = getFileAndCheck(ssTests, "test.xltx"); private static final File xlsEmb = getFileAndCheck(ssTests, "excel_with_embeded.xls"); @@ -150,17 +146,19 @@ public class TestExtractorFactory { @Test(expected = IllegalArgumentException.class) public void testFileInvalid() throws Exception { // Text - try (POITextExtractor te = ExtractorFactory.createExtractor(txt)) {} + try (POITextExtractor ignored = ExtractorFactory.createExtractor(txt)) { + fail("extracting from invalid package"); + } } @Test public void testInputStream() throws Exception { - testStream((f) -> ExtractorFactory.createExtractor(f), true); + testStream(ExtractorFactory::createExtractor, true); } @Test(expected = IllegalArgumentException.class) public void testInputStreamInvalid() throws Exception { - testInvalid((f) -> ExtractorFactory.createExtractor(f)); + testInvalid(ExtractorFactory::createExtractor); } @Test @@ -173,17 +171,6 @@ public class TestExtractorFactory { 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 poifsIS, final boolean loadOOXML) throws IOException, OpenXML4JException, XmlException { for (int i = 0; i < TEST_SET.length; i += 4) { @@ -213,7 +200,8 @@ public class TestExtractorFactory { private void testInvalid(FunctionEx poifs) throws IOException, OpenXML4JException, XmlException { // Text 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 { // Text 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 @@ -452,7 +442,7 @@ public class TestExtractorFactory { }; @Test - public void testFileLeak() throws Exception { + public void testFileLeak() { // run a number of files that might fail in order to catch // leaked file resources when using file-leak-detector while // running the test diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java b/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java index 1f709d969b..5e42300f8b 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java @@ -27,7 +27,6 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; @@ -35,12 +34,10 @@ import java.util.List; import org.apache.poi.POIDataSamples; import org.apache.poi.hslf.usermodel.HSLFObjectShape; 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.hwpf.HWPFDocument; import org.apache.poi.poifs.filesystem.DirectoryNode; 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.sl.extractor.SlideShowExtractor; import org.apache.poi.sl.usermodel.ObjectShape; @@ -68,18 +65,7 @@ public final class TestExtractor { */ private static POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); -// @Before -// 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(); -// } - + @SuppressWarnings("unchecked") private SlideShowExtractor openExtractor(String fileName) throws IOException { try (InputStream is = slTests.openResourceAsStream(fileName)) { 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 * core record, we can still get the rest of the text out - * - * @throws Exception */ @Test public void testMissingCoreRecords() throws IOException { @@ -191,7 +175,7 @@ public final class TestExtractor { assertTrue(dir.hasEntry(HSLFSlideShow.POWERPOINT_DOCUMENT)); 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()); } } @@ -297,7 +281,7 @@ public final class TestExtractor { } 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(); 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")); @@ -399,19 +383,11 @@ public final class TestExtractor { public void testDifferentPOIFS() throws IOException { // Open the two filesystems File pptFile = slTests.getFile("basic_test_ppt_file.ppt"); - try (final InputStream is1 = new FileInputStream(pptFile); - final NPOIFSFileSystem npoifs = new NPOIFSFileSystem(pptFile)) { - - final OPOIFSFileSystem opoifs = new OPOIFSFileSystem(is1); - - DirectoryNode[] files = {opoifs.getRoot(), npoifs.getRoot()}; - + try (final NPOIFSFileSystem npoifs = new NPOIFSFileSystem(pptFile, true)) { // Open directly - for (DirectoryNode dir : files) { - try (SlideShow ppt = SlideShowFactory.create(dir); - SlideShowExtractor extractor = new SlideShowExtractor(ppt)) { - assertEquals(expectText, extractor.getText()); - } + try (SlideShow ppt = SlideShowFactory.create(npoifs.getRoot()); + SlideShowExtractor extractor = new SlideShowExtractor<>(ppt)) { + assertEquals(expectText, extractor.getText()); } } } diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java b/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java index 3cfec195d1..8c8dfa78e0 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/extractor/TestWordExtractor.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; 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.Entry; 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.util.StringUtil; import org.junit.Test; @@ -48,7 +46,7 @@ public final class TestWordExtractor { 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" ) .replaceAll( "\r", "\n" ).trim(); @@ -188,7 +186,8 @@ public final class TestWordExtractor { HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("ThreeColHeadFoot.doc"); 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!"); extractor1.close(); doc1.close(); @@ -197,7 +196,8 @@ public final class TestWordExtractor { HWPFDocument doc2 = HWPFTestDataSamples.openSampleFile("HeaderFooterUnicode.doc"); 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"); extractor2.close(); doc2.close(); @@ -209,7 +209,8 @@ public final class TestWordExtractor { HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("ThreeColHeadFoot.doc"); 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"); extractor1.close(); doc1.close(); @@ -218,7 +219,8 @@ public final class TestWordExtractor { HWPFDocument doc2 = HWPFTestDataSamples.openSampleFile("HeaderFooterUnicode.doc"); 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"); extractor2.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, "Last (4th) paragraph"); + @SuppressWarnings("deprecation") String[] tp = w6e.getParagraphText(); assertEquals(7, tp.length); assertEquals("The quick brown fox jumps over the lazy dog\r\n", tp[0]); @@ -299,17 +302,17 @@ public final class TestWordExtractor { @Test public void testWord6() throws Exception { - InputStream is = docTests.openResourceAsStream("Word6.doc"); - Word6Extractor w6e = new Word6Extractor(is); - is.close(); - String text = w6e.getText(); - - assertContains(text, "The quick brown fox jumps over the lazy dog"); - - String[] tp = w6e.getParagraphText(); - assertEquals(1, tp.length); - assertEquals("The quick brown fox jumps over the lazy dog\r\n", tp[0]); - w6e.close(); + try (InputStream is = docTests.openResourceAsStream("Word6.doc"); + Word6Extractor w6e = new Word6Extractor(is)) { + String text = w6e.getText(); + + assertContains(text, "The quick brown fox jumps over the lazy dog"); + + @SuppressWarnings("deprecation") + String[] tp = w6e.getParagraphText(); + assertEquals(1, tp.length); + assertEquals("The quick brown fox jumps over the lazy dog\r\n", tp[0]); + } } @Test @@ -341,30 +344,23 @@ public final class TestWordExtractor { public void testDifferentPOIFS() throws Exception { // Open the two filesystems File file = docTests.getFile("test2.doc"); - InputStream is = new FileInputStream(file); - OPOIFSFileSystem opoifs = new OPOIFSFileSystem(is); - is.close(); - NPOIFSFileSystem npoifs = new NPOIFSFileSystem(file); - - DirectoryNode[] files = { opoifs.getRoot(), npoifs.getRoot() }; - - // Open directly - for(DirectoryNode dir : files) { - @SuppressWarnings("resource") - WordExtractor extractor = new WordExtractor(dir); - assertEqualsTrim(p_text1_block, extractor.getText()); - // extractor.close(); - } + try (NPOIFSFileSystem npoifs = new NPOIFSFileSystem(file, true)) { + + DirectoryNode dir = npoifs.getRoot(); + + // Open directly + @SuppressWarnings("resource") + WordExtractor extractor1 = new WordExtractor(dir); + assertEqualsTrim(p_text1_block, extractor1.getText()); + // extractor.close(); + + // Open via a HWPFDocument + try (HWPFDocument doc = new HWPFDocument(dir); + 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()) { if ("WordDocument".equals(entry.getName())) { - WordExtractor ex = new WordExtractor(fs); - try { + try (WordExtractor ex = new WordExtractor(fs)) { text = ex.getText(); - } finally { - ex.close(); } } } @@ -396,35 +389,22 @@ public final class TestWordExtractor { @Test public void testExtractorFromWord6Extractor() throws Exception { - InputStream is = POIDataSamples.getHPSFInstance().openResourceAsStream("TestMickey.doc"); - POIFSFileSystem fs = new POIFSFileSystem(is); - is.close(); - Word6Extractor wExt = new Word6Extractor(fs); - try { - POITextExtractor ext = wExt.getMetadataTextExtractor(); - try { - // Now overall - String text = ext.getText(); - assertContains(text, "TEMPLATE = Normal"); - assertContains(text, "SUBJECT = sample subject"); - assertContains(text, "MANAGER = sample manager"); - assertContains(text, "COMPANY = sample company"); - } finally { - ext.close(); - } - } finally { - wExt.close(); - fs.close(); + try (InputStream is = POIDataSamples.getHPSFInstance().openResourceAsStream("TestMickey.doc"); + POIFSFileSystem fs = new POIFSFileSystem(is); + Word6Extractor wExt = new Word6Extractor(fs); + POITextExtractor ext = wExt.getMetadataTextExtractor()) { + // Now overall + String text = ext.getText(); + assertContains(text, "TEMPLATE = Normal"); + assertContains(text, "SUBJECT = sample subject"); + assertContains(text, "MANAGER = sample manager"); + assertContains(text, "COMPANY = sample company"); } } private WordExtractor openExtractor(String fileName) throws IOException { - InputStream is = docTests.openResourceAsStream(fileName); - try { + try (InputStream is = docTests.openResourceAsStream(fileName)) { return new WordExtractor(is); - } finally { - is.close(); } - } } diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java index 76c71bab07..ea9cf893dd 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFWrite.java @@ -32,7 +32,6 @@ import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.HWPFTestCase; import org.apache.poi.hwpf.HWPFTestDataSamples; 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.util.IOUtils; import org.apache.poi.util.TempFile; @@ -99,16 +98,9 @@ public final class TestHWPFWrite extends HWPFTestCase { public void testInPlaceWrite() throws Exception { // Setup as a copy of a known-good file final File file = TempFile.createTempFile("TestDocument", ".doc"); - InputStream inputStream = SAMPLES.openResourceAsStream("SampleDoc.doc"); - try { - FileOutputStream outputStream = new FileOutputStream(file); - try { - IOUtils.copy(inputStream, outputStream); - } finally { - outputStream.close(); - } - } finally { - inputStream.close(); + try (InputStream inputStream = SAMPLES.openResourceAsStream("SampleDoc.doc"); + FileOutputStream outputStream = new FileOutputStream(file)) { + IOUtils.copy(inputStream, outputStream); } // Open from the temp file in read-write mode @@ -136,28 +128,13 @@ public final class TestHWPFWrite extends HWPFTestCase { @Test(expected=IllegalStateException.class) public void testInvalidInPlaceWriteInputStream() throws IOException { // Can't work for InputStream opened files - InputStream is = SAMPLES.openResourceAsStream("SampleDoc.doc"); - HWPFDocument doc = new HWPFDocument(is); - is.close(); - try { + + try (InputStream is = SAMPLES.openResourceAsStream("SampleDoc.doc"); + HWPFDocument doc = new HWPFDocument(is)) { 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) public void testInvalidInPlaceWriteNPOIFS() throws Exception { // Can't work for Read-Only files diff --git a/src/testcases/org/apache/poi/TestPOIDocumentMain.java b/src/testcases/org/apache/poi/TestPOIDocumentMain.java index 8910f4ed52..61597150d4 100644 --- a/src/testcases/org/apache/poi/TestPOIDocumentMain.java +++ b/src/testcases/org/apache/poi/TestPOIDocumentMain.java @@ -31,7 +31,7 @@ import org.apache.poi.hpsf.SummaryInformation; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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.Test; @@ -78,7 +78,7 @@ public final class TestPOIDocumentMain { assertNotNull(doc2.getSummaryInformation()); assertEquals("Avik Sengupta", doc2.getSummaryInformation().getAuthor()); - assertEquals(null, doc2.getSummaryInformation().getKeywords()); + assertNull(doc2.getSummaryInformation().getKeywords()); assertEquals(0, doc2.getDocumentSummaryInformation().getByteCount()); } @@ -110,7 +110,7 @@ public final class TestPOIDocumentMain { // Create a new version ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - OPOIFSFileSystem inFS = new OPOIFSFileSystem(bais); + POIFSFileSystem inFS = new POIFSFileSystem(bais); // Check they're still there POIDocument doc3 = new HPSFPropertiesOnlyDocument(inFS); diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java index 24371855f6..aa2a4cbd74 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java @@ -21,6 +21,7 @@ import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; 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; @@ -28,7 +29,6 @@ import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; 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.PropertySet; import org.apache.poi.hpsf.PropertySetFactory; -import org.apache.poi.hpsf.ReadingNotSupportedException; import org.apache.poi.hpsf.Section; import org.apache.poi.hpsf.SummaryInformation; import org.apache.poi.hpsf.UnsupportedVariantTypeException; @@ -94,8 +93,6 @@ public class TestWrite { "LANG environment variable to a proper value, e.g. " + "\"de_DE\"."; - POIFile[] poiFiles; - @BeforeClass public static void setUp() { VariantSupport.setLogUnsupportedTypes(false); @@ -113,24 +110,20 @@ public class TestWrite { /* Create a mutable property set with a section that does not have the * formatID set: */ - final OutputStream out = new FileOutputStream(filename); - final POIFSFileSystem poiFs = new POIFSFileSystem(); final PropertySet ps = new PropertySet(); ps.clearSections(); ps.addSection(new Section()); /* 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(); ps.write(psStream); psStream.close(); final byte[] streamData = psStream.toByteArray(); poiFs.createDocument(new ByteArrayInputStream(streamData), - SummaryInformation.DEFAULT_STREAM_NAME); + SummaryInformation.DEFAULT_STREAM_NAME); poiFs.writeFilesystem(out); - } finally { - poiFs.close(); - out.close(); } } @@ -170,12 +163,7 @@ public class TestWrite { final POIFSReader r = new POIFSReader(); r.registerListener(new MyPOIFSReaderListener(), SummaryInformation.DEFAULT_STREAM_NAME); - FileInputStream stream = new FileInputStream(filename); - try { - r.read(stream); - } finally { - stream.close(); - } + r.read(filename); } @@ -221,24 +209,16 @@ public class TestWrite { /* Read the POIFS: */ final PropertySet[] psa = new PropertySet[1]; final POIFSReader r = new POIFSReader(); - r.registerListener(new POIFSReaderListener() { - @Override - public void processPOIFSReaderEvent(final POIFSReaderEvent event) { - try { - psa[0] = PropertySetFactory.create(event.getStream()); - } catch (Exception ex) { - fail(ex.getMessage()); - } - }}, - SummaryInformation.DEFAULT_STREAM_NAME - ); - - InputStream stream = new FileInputStream(filename); - try { - r.read(stream); - } finally { - stream.close(); - } + final POIFSReaderListener listener = event -> { + try { + psa[0] = PropertySetFactory.create(event.getStream()); + } catch (Exception ex) { + fail(ex.getMessage()); + } + }; + r.registerListener(listener, SummaryInformation.DEFAULT_STREAM_NAME); + + r.read(filename); assertNotNull(psa[0]); assertTrue(psa[0].isSummaryInformation()); @@ -295,23 +275,17 @@ public class TestWrite { /* Read the POIFS: */ final PropertySet[] psa = new PropertySet[1]; final POIFSReader r = new POIFSReader(); - r.registerListener(new POIFSReaderListener() { - @Override - public void processPOIFSReaderEvent(final POIFSReaderEvent event) { - try { - psa[0] = PropertySetFactory.create(event.getStream()); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - }, - STREAM_NAME); - FileInputStream stream = new FileInputStream(filename); - try { - r.read(stream); - } finally { - stream.close(); - } + final POIFSReaderListener listener = (event) -> { + try { + psa[0] = PropertySetFactory.create(event.getStream()); + } catch (Exception ex) { + fail(ex.getMessage()); + } + }; + + r.registerListener(listener,STREAM_NAME); + r.read(filename); + assertNotNull(psa[0]); Section s = (psa[0].getSections().get(0)); assertEquals(s.getFormatID(), formatID); @@ -338,12 +312,8 @@ public class TestWrite { /** - *

Writes and reads back various variant types and checks whether the - * stuff that has been read back equals the stuff that was written.

- * @throws IOException - * @throws UnsupportedEncodingException - * @throws UnsupportedVariantTypeException - * @throws ReadingNotSupportedException + * Writes and reads back various variant types and checks whether the + * stuff that has been read back equals the stuff that was written. */ @Test public void variantTypes() throws Exception { @@ -379,9 +349,8 @@ public class TestWrite { * was written. */ @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}; for (final int cp : validCodepages) { if (cp == -1 && !hasProperDefaultCharset()) @@ -400,9 +369,8 @@ public class TestWrite { final int[] invalidCodepages = new int[] {0, 1, 2, 4711, 815}; for (int cp : invalidCodepages) { - final long type = (cp == CodePageUtil.CP_UNICODE) ? Variant.VT_LPWSTR : Variant.VT_LPSTR; 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."); } catch (UnsupportedEncodingException ex) { /* This is the expected behaviour. */ @@ -441,7 +409,7 @@ public class TestWrite { } private void checkString(final long variantType, final String value, final int codepage) - throws UnsupportedVariantTypeException, IOException, ReadingNotSupportedException, UnsupportedEncodingException { + throws UnsupportedVariantTypeException, IOException { for (int i=0; iTests writing and reading back a proper dictionary.

- * @throws IOException - * @throws HPSFException */ @Test public void dictionary() throws IOException, HPSFException { @@ -488,9 +454,9 @@ public class TestWrite { final PropertySet ps1 = new PropertySet(); final Section s = ps1.getSections().get(0); final Map m = new HashMap<>(3, 1.0f); - m.put(Long.valueOf(1), "String 1"); - m.put(Long.valueOf(2), "String 2"); - m.put(Long.valueOf(3), "String 3"); + m.put(1L, "String 1"); + m.put(2L, "String 2"); + m.put(3L, "String 3"); s.setDictionary(m); s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]); int codepage = CodePageUtil.CP_UNICODE; @@ -522,12 +488,12 @@ public class TestWrite { */ @Test public void inPlaceNPOIFSWrite() throws Exception { - NPOIFSFileSystem fs = null; - DirectoryEntry root = null; - DocumentNode sinfDoc = null; - DocumentNode dinfDoc = null; - SummaryInformation sinf = null; - DocumentSummaryInformation dinf = null; + NPOIFSFileSystem fs; + DirectoryEntry root; + DocumentNode sinfDoc; + DocumentNode dinfDoc; + SummaryInformation sinf; + DocumentSummaryInformation dinf; // We need to work on a File for in-place changes, so create a temp one final File copy = TempFile.createTempFile("Test-HPSF", "ole2"); @@ -567,10 +533,13 @@ public class TestWrite { assertEquals("\u7b2c1\u7ae0", sinf.getTitle()); assertEquals("", dinf.getCompany()); - assertEquals(null, dinf.getManager()); + assertNull(dinf.getManager()); // Do an in-place replace via an InputStream + assertNotNull(sinfDoc); + assertNotNull(dinfDoc); + new NPOIFSDocument(sinfDoc).replaceContents(sinf.toInputStream()); new NPOIFSDocument(dinfDoc).replaceContents(dinf.toInputStream()); @@ -661,7 +630,7 @@ public class TestWrite { assertEquals("\u7b2c1\u7ae0", sinf.getTitle()); assertEquals("", dinf.getCompany()); - assertEquals(null, dinf.getManager()); + assertNull(dinf.getManager()); // Now alter a few of them @@ -730,43 +699,37 @@ public class TestWrite { // Tidy up fs.close(); + //noinspection ResultOfMethodCallIgnored copy.delete(); } /** - *

Tests writing and reading back a proper dictionary with an invalid - * codepage. (HPSF writes Unicode dictionaries only.)

- * @throws IOException - * @throws HPSFException + * Tests writing and reading back a proper dictionary with an invalid + * codepage. (HPSF writes Unicode dictionaries only.) */ - @Test(expected=IllegalPropertySetDataException.class) + @Test(expected=UnsupportedEncodingException.class) public void dictionaryWithInvalidCodepage() throws IOException, HPSFException { final File copy = TempFile.createTempFile("Test-HPSF", "ole2"); copy.deleteOnExit(); /* Write: */ - final OutputStream out = new FileOutputStream(copy); - - final POIFSFileSystem poiFs = new POIFSFileSystem(); + final PropertySet ps1 = new PropertySet(); final Section s = ps1.getSections().get(0); final Map m = new HashMap<>(3, 1.0f); - m.put(Long.valueOf(1), "String 1"); - m.put(Long.valueOf(2), "String 2"); - m.put(Long.valueOf(3), "String 3"); + m.put(1L, "String 1"); + m.put(2L, "String 2"); + m.put(3L, "String 3"); - try { + try (OutputStream out = new FileOutputStream(copy); + POIFSFileSystem poiFs = new POIFSFileSystem()) { s.setDictionary(m); s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]); int codepage = 12345; - s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, - Integer.valueOf(codepage)); + s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage); poiFs.createDocument(ps1.toInputStream(), "Test"); poiFs.writeFilesystem(out); - } finally { - poiFs.close(); - out.close(); } } diff --git a/src/testcases/org/apache/poi/hpsf/basic/Util.java b/src/testcases/org/apache/poi/hpsf/basic/Util.java index daa58d789d..af4e4462a9 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/Util.java +++ b/src/testcases/org/apache/poi/hpsf/basic/Util.java @@ -18,8 +18,9 @@ package org.apache.poi.hpsf.basic; +import static org.junit.Assert.fail; + import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -28,7 +29,6 @@ import java.util.List; import org.apache.poi.hpsf.PropertySet; 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.util.IOUtils; @@ -39,6 +39,9 @@ import org.apache.poi.util.IOUtils; */ final class Util { + private Util() { + } + /** *

Reads a set of files from a POI filesystem and returns them * 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 */ - public static List readPOIFiles(final File poiFs, final String... poiFiles) - throws FileNotFoundException, IOException { + static List readPOIFiles(final File poiFs, final String... poiFiles) throws IOException { final List files = new ArrayList<>(); POIFSReader r = new POIFSReader(); - POIFSReaderListener pfl = new POIFSReaderListener() { - @Override - public void processPOIFSReaderEvent(final POIFSReaderEvent event) { - try { - final POIFile f = new POIFile(); - f.setName(event.getName()); - f.setPath(event.getPath()); - final InputStream in = event.getStream(); - f.setBytes(IOUtils.toByteArray(in)); - in.close(); - files.add(f); - } catch (IOException ex) { - throw new RuntimeException(ex); - } + POIFSReaderListener pfl = event -> { + try { + final POIFile f = new POIFile(); + f.setName(event.getName()); + f.setPath(event.getPath()); + final InputStream in = event.getStream(); + f.setBytes(IOUtils.toByteArray(in)); + in.close(); + files.add(f); + } catch (IOException ex) { + fail(ex.getMessage()); } }; if (poiFiles.length == 0) { @@ -88,12 +87,8 @@ final class Util { } /* Read the POI filesystem. */ - FileInputStream stream = new FileInputStream(poiFs); - try { - r.read(stream); - } finally { - stream.close(); - } + r.read(poiFs); + return files; } @@ -110,29 +105,23 @@ final class Util { * @return The property sets. The elements are ordered in the same way * 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 */ - public static List readPropertySets(final File poiFs) throws IOException { + static List readPropertySets(final File poiFs) throws IOException { final List files = new ArrayList<>(7); final POIFSReader r = new POIFSReader(); - POIFSReaderListener pfl = new POIFSReaderListener() { - @Override - public void processPOIFSReaderEvent(final POIFSReaderEvent event) { - try { - final POIFile f = new POIFile(); - f.setName(event.getName()); - f.setPath(event.getPath()); - final InputStream in = event.getStream(); - if (PropertySet.isPropertySetStream(in)) { - f.setBytes(IOUtils.toByteArray(in)); - files.add(f); - } - } catch (Exception ex) { - throw new RuntimeException(ex); + final POIFSReaderListener pfl = event -> { + try { + final POIFile f = new POIFile(); + f.setName(event.getName()); + f.setPath(event.getPath()); + final InputStream in = event.getStream(); + if (PropertySet.isPropertySetStream(in)) { + f.setBytes(IOUtils.toByteArray(in)); + files.add(f); } + } catch (Exception ex) { + fail(ex.getMessage()); } }; @@ -140,12 +129,7 @@ final class Util { r.registerListener(pfl); /* Read the POI filesystem. */ - InputStream is = new FileInputStream(poiFs); - try { - r.read(is); - } finally { - is.close(); - } + r.read(poiFs); return files; } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index 53802f5069..f7c8682d3e 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -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.DocumentInputStream; 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.ss.formula.ptg.Area3DPtg; 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.util.CellRangeAddress; import org.apache.poi.util.LocaleUtil; -import org.junit.After; import org.junit.Assume; import org.junit.Ignore; import org.junit.Test; @@ -1022,7 +1020,7 @@ public final class TestBugs extends BaseTestBugzillaIssues { assertEquals(4, wb.getNumberOfFontsAsInt()); - HSSFFont f1 = wb.getFontAt((short) 0); + HSSFFont f1 = wb.getFontAt(0); assertFalse(f1.getBold()); // Check that asking for the same font @@ -1617,7 +1615,7 @@ public final class TestBugs extends BaseTestBugzillaIssues { @Test public void bug46904() throws Exception { try { - OPOIFSFileSystem fs = new OPOIFSFileSystem( + POIFSFileSystem fs = new POIFSFileSystem( HSSFITestDataProvider.instance.openWorkbookStream("46904.xls")); new HSSFWorkbook(fs.getRoot(), false).close(); fail("Should catch exception here"); @@ -2505,7 +2503,7 @@ public final class TestBugs extends BaseTestBugzillaIssues { @Test 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); assertEquals(wb1.getAllPictures().size(), 1); wb1.close(); @@ -2513,13 +2511,13 @@ public final class TestBugs extends BaseTestBugzillaIssues { wb1.close(); wb1 = new HSSFWorkbook(); - Workbook wb2 = writeOutAndReadBack((HSSFWorkbook) wb1); + HSSFWorkbook wb2 = writeOutAndReadBack(wb1); wb1.close(); assertEquals(wb2.getAllPictures().size(), 0); wb2.addPicture(new byte[]{123, 22}, Workbook.PICTURE_TYPE_JPEG); assertEquals(wb2.getAllPictures().size(), 1); - Workbook wb3 = writeOutAndReadBack((HSSFWorkbook) wb2); + HSSFWorkbook wb3 = writeOutAndReadBack(wb2); wb2.close(); assertEquals(wb3.getAllPictures().size(), 1); @@ -3093,8 +3091,8 @@ public final class TestBugs extends BaseTestBugzillaIssues { @Test public void test61287() throws IOException { - final Workbook wb = HSSFTestDataSamples.openSampleWorkbook("61287.xls"); - ExcelExtractor ex = new ExcelExtractor((HSSFWorkbook) wb); + final HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("61287.xls"); + ExcelExtractor ex = new ExcelExtractor(wb); String text = ex.getText(); assertContains(text, "\u8D44\u4EA7\u8D1F\u503A\u8868"); wb.close(); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java index fdcd8b21a8..7450581f5b 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java @@ -29,7 +29,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -38,7 +37,6 @@ import java.util.Collection; import java.util.List; import junit.framework.AssertionFailedError; - import org.apache.poi.POIDataSamples; import org.apache.poi.ddf.EscherBSERecord; 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.DirectoryNode; 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.ss.formula.ptg.Area3DPtg; import org.apache.poi.ss.usermodel.BaseTestWorkbook; @@ -95,7 +92,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { /** * Tests for {@link HSSFWorkbook#isHidden()} etc - * @throws IOException */ @Test public void hidden() throws IOException { @@ -103,23 +99,23 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { WindowOneRecord w1 = wb.getWorkbook().getWindowOne(); - assertEquals(false, wb.isHidden()); - assertEquals(false, w1.getHidden()); + assertFalse(wb.isHidden()); + assertFalse(w1.getHidden()); wb.setHidden(true); - assertEquals(true, wb.isHidden()); - assertEquals(true, w1.getHidden()); + assertTrue(wb.isHidden()); + assertTrue(w1.getHidden()); HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb); w1 = wbBack.getWorkbook().getWindowOne(); wbBack.setHidden(true); - assertEquals(true, wbBack.isHidden()); - assertEquals(true, w1.getHidden()); + assertTrue(wbBack.isHidden()); + assertTrue(w1.getHidden()); wbBack.setHidden(false); - assertEquals(false, wbBack.isHidden()); - assertEquals(false, w1.getHidden()); + assertFalse(wbBack.isHidden()); + assertFalse(w1.getHidden()); wbBack.close(); wb.close(); @@ -257,30 +253,30 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { wb.setSelectedTabs(selected); assertCollectionsEquals(selected, wb.getSelectedTabs()); - assertEquals(true, sheet0.isSelected()); - assertEquals(false, sheet1.isSelected()); - assertEquals(true, sheet2.isSelected()); - assertEquals(true, sheet3.isSelected()); - assertEquals(false, sheet4.isSelected()); - assertEquals(false, sheet5.isSelected()); + assertTrue(sheet0.isSelected()); + assertFalse(sheet1.isSelected()); + assertTrue(sheet2.isSelected()); + assertTrue(sheet3.isSelected()); + assertFalse(sheet4.isSelected()); + assertFalse(sheet5.isSelected()); selected = arrayToList(new int[] { 1, 3, 5 }); wb.setSelectedTabs(selected); // previous selection should be cleared assertCollectionsEquals(selected, wb.getSelectedTabs()); - assertEquals(false, sheet0.isSelected()); - assertEquals(true, sheet1.isSelected()); - assertEquals(false, sheet2.isSelected()); - assertEquals(true, sheet3.isSelected()); - assertEquals(false, sheet4.isSelected()); - assertEquals(true, sheet5.isSelected()); - - assertEquals(true, sheet0.isActive()); - assertEquals(false, sheet2.isActive()); + assertFalse(sheet0.isSelected()); + assertTrue(sheet1.isSelected()); + assertFalse(sheet2.isSelected()); + assertTrue(sheet3.isSelected()); + assertFalse(sheet4.isSelected()); + assertTrue(sheet5.isSelected()); + + assertTrue(sheet0.isActive()); + assertFalse(sheet2.isActive()); wb.setActiveSheet(2); - assertEquals(false, sheet0.isActive()); - assertEquals(true, sheet2.isActive()); + assertFalse(sheet0.isActive()); + assertTrue(sheet2.isActive()); /*{ // helpful if viewing this workbook in excel: 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 * 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 - * @throws IOException */ @Test 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() */ private static final class BadlyBehavedRecord extends Record { - public BadlyBehavedRecord() { + BadlyBehavedRecord() { // } @Override @@ -576,7 +571,7 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { POIFSFileSystem fs2 = new POIFSFileSystem(new ByteArrayInputStream(bytes)); ClassID clsid2 = fs2.getRoot().getStorageClsid(); - assertTrue(clsid1.equals(clsid2)); + assertEquals(clsid1, clsid2); fs2.close(); wb.close(); @@ -625,108 +620,89 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { public void differentPOIFS() throws Exception { // Open the two filesystems DirectoryNode[] files = new DirectoryNode[2]; - POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("Simple.xls")); - try { - files[0] = poifsFileSystem.getRoot(); - NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("Simple.xls")); - try { - files[1] = npoifsFileSystem.getRoot(); - - // Open without preserving nodes - for(DirectoryNode dir : files) { - HSSFWorkbook workbook = new HSSFWorkbook(dir, false); - HSSFSheet sheet = workbook.getSheetAt(0); - HSSFCell cell = sheet.getRow(0).getCell(0); - assertEquals("replaceMe", cell .getRichStringCellValue().getString()); - - workbook.close(); - } - - // Now re-check with preserving - for(DirectoryNode dir : files) { - HSSFWorkbook workbook = new HSSFWorkbook(dir, true); - HSSFSheet sheet = workbook.getSheetAt(0); - HSSFCell cell = sheet.getRow(0).getCell(0); - assertEquals("replaceMe", cell .getRichStringCellValue().getString()); - - workbook.close(); - } - } finally { - npoifsFileSystem.close(); - } - } finally { - poifsFileSystem.close(); - } + try (POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("Simple.xls"))) { + files[0] = poifsFileSystem.getRoot(); + try (NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("Simple.xls"))) { + files[1] = npoifsFileSystem.getRoot(); + + // Open without preserving nodes + for (DirectoryNode dir : files) { + HSSFWorkbook workbook = new HSSFWorkbook(dir, false); + HSSFSheet sheet = workbook.getSheetAt(0); + HSSFCell cell = sheet.getRow(0).getCell(0); + assertEquals("replaceMe", cell.getRichStringCellValue().getString()); + + workbook.close(); + } + + // Now re-check with preserving + for (DirectoryNode dir : files) { + HSSFWorkbook workbook = new HSSFWorkbook(dir, true); + HSSFSheet sheet = workbook.getSheetAt(0); + HSSFCell cell = sheet.getRow(0).getCell(0); + assertEquals("replaceMe", cell.getRichStringCellValue().getString()); + + workbook.close(); + } + } + } } @Test public void wordDocEmbeddedInXls() throws IOException { // Open the two filesystems DirectoryNode[] files = new DirectoryNode[2]; - POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls")); - try { - files[0] = poifsFileSystem.getRoot(); - NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("WithEmbeddedObjects.xls")); - try { - files[1] = npoifsFileSystem.getRoot(); - - // Check the embedded parts - for(DirectoryNode root : files) { - HSSFWorkbook hw = new HSSFWorkbook(root, true); - List objects = hw.getAllEmbeddedObjects(); - boolean found = false; - for (HSSFObjectData embeddedObject : objects) { - if (embeddedObject.hasDirectoryEntry()) { - DirectoryEntry dir = embeddedObject.getDirectory(); - if (dir instanceof DirectoryNode) { - DirectoryNode dNode = (DirectoryNode) dir; - if (hasEntry(dNode, "WordDocument")) { - found = true; - } - } - } - } - assertTrue(found); - - hw.close(); - } - } finally { - npoifsFileSystem.close(); - } - } finally { - poifsFileSystem.close(); - } + try (POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls"))) { + files[0] = poifsFileSystem.getRoot(); + try (NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(HSSFTestDataSamples.getSampleFile("WithEmbeddedObjects.xls"))) { + files[1] = npoifsFileSystem.getRoot(); + + // Check the embedded parts + for (DirectoryNode root : files) { + HSSFWorkbook hw = new HSSFWorkbook(root, true); + List objects = hw.getAllEmbeddedObjects(); + boolean found = false; + for (HSSFObjectData embeddedObject : objects) { + if (embeddedObject.hasDirectoryEntry()) { + DirectoryEntry dir = embeddedObject.getDirectory(); + if (dir instanceof DirectoryNode) { + DirectoryNode dNode = (DirectoryNode) dir; + if (dNode.hasEntry("WordDocument")) { + found = true; + break; + } + } + } + } + assertTrue(found); + + hw.close(); + } + } + } } /** * Checks that we can open a workbook with NPOIFS, and write it out * again (via POIFS) and have it be valid - * @throws IOException */ @Test public void writeWorkbookFromNPOIFS() throws IOException { - InputStream is = HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls"); - try { - NPOIFSFileSystem fs = new NPOIFSFileSystem(is); - try { - // Start as NPOIFS - HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true); - assertEquals(3, wb.getNumberOfSheets()); - assertEquals("Root xls", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue()); - - // Will switch to POIFS - HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb); - assertEquals(3, wbBack.getNumberOfSheets()); - assertEquals("Root xls", wbBack.getSheetAt(0).getRow(0).getCell(0).getStringCellValue()); - wbBack.close(); - - wb.close(); - } finally { - fs.close(); - } - } finally { - is.close(); - } + try (InputStream is = HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls"); + NPOIFSFileSystem fs = new NPOIFSFileSystem(is)) { + // Start as NPOIFS + HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true); + assertEquals(3, wb.getNumberOfSheets()); + assertEquals("Root xls", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue()); + + // Will switch to POIFS + HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb); + assertEquals(3, wbBack.getNumberOfSheets()); + assertEquals("Root xls", wbBack.getSheetAt(0).getRow(0).getCell(0).getStringCellValue()); + wbBack.close(); + + wb.close(); + } } @Test @@ -795,7 +771,9 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { wb.setSheetOrder("other sheet", 0); // names + //noinspection ConstantConditions assertEquals("'first sheet'!D1", wb.getName("name1").getRefersToFormula()); + //noinspection ConstantConditions assertEquals("'other sheet'!C1", wb.getName("name2").getRefersToFormula()); // cells @@ -811,15 +789,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { wb.close(); } - private boolean hasEntry(DirectoryNode dirNode, String entryName) { - try { - dirNode.getEntry(entryName); - return true; - } catch (FileNotFoundException e) { - return false; - } - } - @Test public void clonePictures() throws IOException { HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithImages.xls"); @@ -854,11 +823,8 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { // Should throw exception about invalid POIFSFileSystem @Test(expected=IllegalArgumentException.class) public void emptyDirectoryNode() throws IOException { - POIFSFileSystem fs = new POIFSFileSystem(); - try { + try (POIFSFileSystem fs = new POIFSFileSystem()) { new HSSFWorkbook(fs).close(); - } finally { - fs.close(); } } @@ -1093,7 +1059,8 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { 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); assertNotNull(hssfName); assertEquals(expect, hssfName.getRefersToFormula()); @@ -1149,16 +1116,13 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { // edit the workbook { - NPOIFSFileSystem fs = new NPOIFSFileSystem(file, false); - try { + try (NPOIFSFileSystem fs = new NPOIFSFileSystem(file, false)) { DirectoryNode root = fs.getRoot(); final Workbook workbook = new HSSFWorkbook(root, true); final Sheet sheet = workbook.getSheet("foo"); sheet.getRow(1).createCell(2).setCellValue("baz"); - + writeAndCloseWorkbook(workbook, file); - } finally { - fs.close(); } } } finally { @@ -1239,18 +1203,6 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { } 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 NPOIFSFileSystem fs = new NPOIFSFileSystem( POIDataSamples.getSpreadSheetInstance().getFile("SampleSS.xls"), true); @@ -1268,16 +1220,9 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook { public void inPlaceWrite() throws Exception { // Setup as a copy of a known-good file final File file = TempFile.createTempFile("TestHSSFWorkbook", ".xls"); - InputStream inputStream = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SampleSS.xls"); - try { - FileOutputStream outputStream = new FileOutputStream(file); - try { - IOUtils.copy(inputStream, outputStream); - } finally { - outputStream.close(); - } - } finally { - inputStream.close(); + try (InputStream inputStream = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SampleSS.xls"); + FileOutputStream outputStream = new FileOutputStream(file)) { + IOUtils.copy(inputStream, outputStream); } // Open from the temp file in read-write mode diff --git a/src/testcases/org/apache/poi/poifs/eventfilesystem/TestPOIFSReaderRegistry.java b/src/testcases/org/apache/poi/poifs/eventfilesystem/TestPOIFSReaderRegistry.java index d920d2ce8c..7b88fbc650 100644 --- a/src/testcases/org/apache/poi/poifs/eventfilesystem/TestPOIFSReaderRegistry.java +++ b/src/testcases/org/apache/poi/poifs/eventfilesystem/TestPOIFSReaderRegistry.java @@ -17,20 +17,22 @@ 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.Iterator; import java.util.Set; -import junit.framework.TestCase; - import org.apache.poi.poifs.filesystem.POIFSDocumentPath; +import org.junit.Test; /** * Class to test POIFSReaderRegistry functionality * * @author Marc Johnson */ -public final class TestPOIFSReaderRegistry extends TestCase { +public final class TestPOIFSReaderRegistry { private final POIFSReaderListener[] listeners = { new Listener(), new Listener(), new Listener(), new Listener() @@ -56,13 +58,14 @@ public final class TestPOIFSReaderRegistry extends TestCase { /** * Test empty registry */ + @Test public void testEmptyRegistry() { POIFSReaderRegistry registry = new POIFSReaderRegistry(); for (POIFSDocumentPath path : paths) { for (String name : names) { Iterator listeners = - registry.getListeners(path, name); + registry.getListeners(path, name).iterator(); assertTrue(!listeners.hasNext()); } @@ -72,6 +75,7 @@ public final class TestPOIFSReaderRegistry extends TestCase { /** * Test mixed registration operations */ + @Test public void testMixedRegistrationOperations() { POIFSReaderRegistry registry = new POIFSReaderRegistry(); @@ -93,21 +97,20 @@ public final class TestPOIFSReaderRegistry extends TestCase { { for (int n = 0; n < names.length; n++) { - Iterator listeners = + Iterable listeners = registry.getListeners(paths[ k ], names[ n ]); if (k == n) { - assertTrue(!listeners.hasNext()); + assertTrue(!listeners.iterator().hasNext()); } else { Set registeredListeners = new HashSet<>(); - while (listeners.hasNext()) - { - registeredListeners.add(listeners.next()); + for (POIFSReaderListener rl : listeners) { + registeredListeners.add(rl); } assertEquals(this.listeners.length - 1, registeredListeners.size()); @@ -132,14 +135,13 @@ public final class TestPOIFSReaderRegistry extends TestCase { } for (POIFSDocumentPath path : paths) { for (String name : names) { - Iterator listeners = + Iterable listeners = registry.getListeners(path, name); Set registeredListeners = new HashSet<>(); - while (listeners.hasNext()) - { - registeredListeners.add(listeners.next()); + for (POIFSReaderListener rl : listeners) { + registeredListeners.add(rl); } assertEquals(this.listeners.length, registeredListeners.size()); diff --git a/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java b/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java index 871aada677..7f071886d2 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/AllPOIFSFileSystemTests.java @@ -21,7 +21,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; /** - * Tests for org.apache.poi.poifs.filesystem
+ * Tests for org.apache.poi.poifs.filesystem */ @RunWith(Suite.class) @Suite.SuiteClasses({ @@ -29,7 +29,6 @@ import org.junit.runners.Suite; , TestDocument.class , TestDocumentDescriptor.class , TestDocumentInputStream.class - , TestDocumentNode.class , TestDocumentOutputStream.class , TestEmptyDocument.class , TestNotOLE2Exception.class diff --git a/src/testcases/org/apache/poi/poifs/filesystem/ReaderWriter.java b/src/testcases/org/apache/poi/poifs/filesystem/ReaderWriter.java index 240e945a5d..ed2ce941ab 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/ReaderWriter.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/ReaderWriter.java @@ -19,7 +19,7 @@ package org.apache.poi.poifs.filesystem; -import java.io.FileInputStream; +import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -38,42 +38,19 @@ import org.apache.poi.util.IOUtils; * @author Marc Johnson (mjohnson at apache dot org) */ -public class ReaderWriter +public final class ReaderWriter implements POIFSReaderListener, POIFSWriterListener { - private final POIFSFileSystem filesystem; private final DirectoryEntry root; // keys are DocumentDescriptors, values are byte[]s - private final Map dataMap; + private final Map dataMap = new HashMap<>(); - /** - * Constructor ReaderWriter - * - * - * @param filesystem - * - */ - - ReaderWriter(final POIFSFileSystem filesystem) - { - this.filesystem = filesystem; - root = this.filesystem.getRoot(); - dataMap = new HashMap<>(); + private ReaderWriter(final POIFSFileSystem filesystem) { + root = filesystem.getRoot(); } - /** - * Method main - * - * - * @param args - * - * @exception IOException - * - */ - - public static void main(String [] args) - throws IOException + public static void main(String [] args) throws IOException { if (args.length != 2) { @@ -86,10 +63,8 @@ public class ReaderWriter POIFSFileSystem filesystem = new POIFSFileSystem(); reader.registerListener(new ReaderWriter(filesystem)); - FileInputStream istream = new FileInputStream(args[ 0 ]); - reader.read(istream); - istream.close(); + reader.read(new File(args[ 0 ])); FileOutputStream ostream = new FileOutputStream(args[ 1 ]); filesystem.writeFilesystem(ostream); diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestDocument.java b/src/testcases/org/apache/poi/poifs/filesystem/TestDocument.java index f670b9a668..14422e5b74 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestDocument.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestDocument.java @@ -17,218 +17,131 @@ 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.ByteArrayOutputStream; 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.storage.RawDataBlock; - -import junit.framework.TestCase; +import org.apache.poi.poifs.storage.RawDataUtil; +import org.apache.poi.util.IOUtils; +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 */ - public void testOPOIFSDocument() throws IOException { + @Test + public void testNPOIFSDocument() throws IOException { - // verify correct number of blocks get created for document - // that is exact multituple of block size - OPOIFSDocument document; - byte[] array = new byte[ 4096 ]; + try (NPOIFSFileSystem poifs = new NPOIFSFileSystem()) { - for (int j = 0; j < array.length; j++) - { - array[ j ] = ( byte ) j; - } - document = new OPOIFSDocument("foo", new SlowInputStream(new ByteArrayInputStream(array))); - checkDocument(document, array); - - // verify correct number of blocks get created for document - // that is not an exact multiple of block size - array = new byte[ 4097 ]; - 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 - // that is small - array = new byte[ 4095 ]; - 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 - // that is rather small - array = new byte[ 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); - byte[] output = stream.toByteArray(); - byte[] array2 = - { - ( 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); - for (int j = 0; j < output.length; j++) - { - assertEquals("Checking property offset " + j, array2[ j ], - output[ j ]); - } - } + // verify correct number of blocks get created for document + // that is exact multiple of block size + checkDocument(poifs, LARGER_BIG_BLOCK_SIZE); - private static OPOIFSDocument makeCopy(OPOIFSDocument document, byte[] input, byte[] data) - throws IOException { - OPOIFSDocument copy = null; - - if (input.length >= 4096) - { - RawDataBlock[] blocks = - new RawDataBlock[ (input.length + 511) / 512 ]; - ByteArrayInputStream stream = new ByteArrayInputStream(data); - int index = 0; - - while (true) - { - RawDataBlock block = new RawDataBlock(stream); - - if (block.eof()) - { - break; - } - blocks[ index++ ] = block; - } - copy = new OPOIFSDocument("test" + input.length, blocks, - input.length); - } - else - { - copy = new OPOIFSDocument("test"+input.length, document.getSmallBlocks(), input.length); + // verify correct number of blocks get created for document + // that is not an exact multiple of block size + checkDocument(poifs, LARGER_BIG_BLOCK_SIZE + 1); + + // verify correct number of blocks get created for document + // that is small + checkDocument(poifs, LARGER_BIG_BLOCK_SIZE - 1); + + // verify correct number of blocks get created for document + // that is rather small + checkDocument(poifs, 199); + + + // verify that output is correct + NPOIFSDocument document = checkDocument(poifs, LARGER_BIG_BLOCK_SIZE + 1); + DocumentProperty property = document.getDocumentProperty(); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + property.writeData(stream); + byte[] output = stream.toByteArray(); + byte[] array2 = RawDataUtil.decompress("H4sIAAAAAAAAAEtlyGMoYShiqGSwYCAH8DEwMf5HAsToMQdiRgEIGwCDyzEQgAAAAA=="); + + assertArrayEquals(array2, output); } - return copy; } - private static void checkDocument(final OPOIFSDocument document, final byte[] input) - throws IOException { - int big_blocks = 0; - int small_blocks = 0; - int total_output = 0; + private static NPOIFSDocument checkDocument(final NPOIFSFileSystem poifs, final int size) throws IOException { + final byte[] input = new byte[size]; + IntStream.range(0, size).forEach(i -> input[i] = (byte)i); - if (input.length >= 4096) - { - big_blocks = (input.length + 511) / 512; - total_output = big_blocks * 512; - } - else - { - small_blocks = (input.length + 63) / 64; - total_output = 0; + NPOIFSDocument document = ((DocumentNode)poifs.createDocument( + new SlowInputStream(new ByteArrayInputStream(input)), + "entry"+poifs.getRoot().getEntryCount())).getDocument(); + + final int blockSize = (size >= 4096) ? 512 : 64; + final int blockCount = (size + (blockSize-1)) / blockSize; + + final byte[] bytCpy = checkValues(blockCount, document, input); + final NPOIFSDocument copied = makeCopy(document,bytCpy); + + checkValues(blockCount, copied, input); + + return document; + } + + private static NPOIFSDocument makeCopy(NPOIFSDocument document, byte[] input) throws IOException { + NPOIFSFileSystem poifs = document.getFileSystem(); + String name = "test" + input.length; + DirectoryNode root = poifs.getRoot(); + if (root.hasEntry(name)) { + root.deleteEntry((EntryNode)root.getEntry(name)); } - checkValues( - big_blocks, small_blocks, total_output, - makeCopy( - document, input, - checkValues( - big_blocks, small_blocks, total_output, document, - input)), input); + return ((DocumentNode)root + .createDocument(name, new ByteArrayInputStream(input))) + .getDocument(); } - private static byte[] checkValues(int big_blocks, int small_blocks, int total_output, - OPOIFSDocument document, byte[] input) throws IOException { + private static byte[] checkValues(final int blockCountExp, NPOIFSDocument document, byte[] input) throws IOException { + assertNotNull(document); + assertNotNull(document.getDocumentProperty().getDocument()); assertEquals(document, document.getDocumentProperty().getDocument()); - int increment = ( int ) Math.sqrt(input.length); - - for (int j = 1; j <= input.length; j += increment) - { - byte[] buffer = new byte[ j ]; - int offset = 0; - - for (int k = 0; k < (input.length / j); k++) - { - document.read(buffer, offset); - for (int n = 0; n < buffer.length; n++) - { - assertEquals("checking byte " + (k * j) + n, - input[ (k * j) + n ], buffer[ n ]); - } - offset += j; - } - } - assertEquals(big_blocks, document.countBlocks()); - assertEquals(small_blocks, document.getSmallBlocks().length); - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - document.writeBlocks(stream); - byte[] output = stream.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(input); - assertEquals(total_output, output.length); - int limit = Math.min(total_output, input.length); + int blockCountAct = 0, bytesRemaining = input.length; + for (ByteBuffer bb : document) { + assertTrue(bytesRemaining > 0); + int bytesAct = Math.min(bb.remaining(), bytesRemaining); + assertTrue(bytesAct <= document.getDocumentBlockSize()); + byte[] bufAct = new byte[bytesAct]; + bb.get(bufAct); - for (int j = 0; j < limit; j++) - { - assertEquals("Checking document offset " + j, input[ j ], - output[ j ]); + byte[] bufExp = new byte[bytesAct]; + int bytesExp = bis.read(bufExp, 0, bytesAct); + assertEquals(bytesExp, bytesAct); + + assertArrayEquals(bufExp, bufAct); + blockCountAct++; + bytesRemaining -= bytesAct; } - for (int j = limit; j < output.length; j++) - { - assertEquals("Checking document offset " + j, ( byte ) -1, - output[ j ]); + + assertEquals(blockCountExp, blockCountAct); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try (DocumentInputStream dis = document.getFileSystem().createDocumentInputStream( + document.getDocumentProperty().getName())) { + IOUtils.copy(dis, stream); } + + byte[] output = stream.toByteArray(); + assertArrayEquals(input, stream.toByteArray()); return output; } } diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java b/src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java index a4b64c56e2..87a122f4d3 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java @@ -18,19 +18,17 @@ package org.apache.poi.poifs.filesystem; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; 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.junit.Before; import org.junit.Test; @@ -39,448 +37,369 @@ import org.junit.Test; * Class to test DocumentInputStream functionality */ public final class TestDocumentInputStream { - private DocumentNode _workbook_n; - private DocumentNode _workbook_o; - private byte[] _workbook_data; - private static final int _workbook_size = 5000; + private DocumentNode _workbook_n; + private byte[] _workbook_data; + private static final int _workbook_size = 5000; - // non-even division of _workbook_size, also non-even division of - // any block size - private static final int _buffer_size = 6; + // non-even division of _workbook_size, also non-even division of + // any block size + private static final int _buffer_size = 6; - @Before - public void setUp() throws Exception { + @Before + public void setUp() throws Exception { int blocks = (_workbook_size + 511) / 512; - _workbook_data = new byte[ 512 * blocks ]; - Arrays.fill(_workbook_data, ( byte ) -1); - for (int j = 0; j < _workbook_size; j++) - { - _workbook_data[ j ] = ( byte ) (j * j); + _workbook_data = new byte[512 * blocks]; + Arrays.fill(_workbook_data, (byte) -1); + for (int j = 0; j < _workbook_size; 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 byte[] _workbook_data_only = new byte[_workbook_size]; System.arraycopy(_workbook_data, 0, _workbook_data_only, 0, _workbook_size); - + NPOIFSFileSystem npoifs = new NPOIFSFileSystem(); // Make it easy when debugging to see what isn't the doc byte[] minus1 = new byte[512]; - Arrays.fill(minus1, (byte)-1); + Arrays.fill(minus1, (byte) -1); npoifs.getBlockAt(-1).put(minus1); npoifs.getBlockAt(0).put(minus1); npoifs.getBlockAt(1).put(minus1); - + // Create the NPOIFS document - _workbook_n = (DocumentNode)npoifs.createDocument( - new ByteArrayInputStream(_workbook_data_only), - "Workbook" + _workbook_n = (DocumentNode) npoifs.createDocument( + new ByteArrayInputStream(_workbook_data_only), + "Workbook" ); } - /** + /** * test constructor */ @Test public void testConstructor() throws IOException { - DocumentInputStream ostream = new ODocumentInputStream(_workbook_o); - DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); - - 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(); + try (DocumentInputStream nstream = new NDocumentInputStream(_workbook_n)) { + assertEquals(_workbook_size, _workbook_n.getSize()); + assertEquals(_workbook_size, available(nstream)); + } } /** * test available() behavior */ - @Test + @Test(expected = IllegalStateException.class) public void testAvailable() throws IOException { - DocumentInputStream ostream = new DocumentInputStream(_workbook_o); DocumentInputStream nstream = new NDocumentInputStream(_workbook_n); - - assertEquals(_workbook_size, available(ostream)); assertEquals(_workbook_size, available(nstream)); - ostream.close(); nstream.close(); - - try { - 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 - } + + available(nstream); } /** * test mark/reset/markSupported. */ + @SuppressWarnings("ResultOfMethodCallIgnored") @Test 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]; - - DocumentInputStream[] streams = new DocumentInputStream[] { - new DocumentInputStream(_workbook_o), - new NDocumentInputStream(_workbook_n) - }; - for(DocumentInputStream stream : streams) { - // Read a fifth of it, and check all's correct - stream.read(buffer); - 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]); - } + + DocumentInputStream stream = new NDocumentInputStream(_workbook_n); + // Read a fifth of it, and check all's correct + stream.read(buffer); + 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]); + } + // Now repeat it with spanning multiple blocks - streams = new DocumentInputStream[] { - new DocumentInputStream(_workbook_o), - new NDocumentInputStream(_workbook_n) - }; - for(DocumentInputStream stream : streams) { - // Read several blocks work - buffer = new byte[ _workbook_size / 5 ]; - stream.read(buffer); - 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()); + stream = new NDocumentInputStream(_workbook_n); + // Read several blocks work + buffer = new byte[_workbook_size / 5]; + stream.read(buffer); + 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()); } /** * test simple read method */ - @Test + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test(expected = IOException.class) public void testReadSingleByte() throws IOException { - DocumentInputStream[] streams = new DocumentInputStream[] { - new DocumentInputStream(_workbook_o), - new NDocumentInputStream(_workbook_n) - }; - for(DocumentInputStream stream : streams) { - int remaining = _workbook_size; - - // Try and read each byte in turn - for (int j = 0; j < _workbook_size; j++) { - int b = stream.read(); - assertTrue("checking sign of " + j, b >= 0); - assertEquals("validating byte " + j, _workbook_data[ j ], - ( byte ) b); - remaining--; - assertEquals("checking remaining after reading byte " + j, - remaining, available(stream)); - } - - // Ensure we fell off the end - assertEquals(-1, stream.read()); - - // Check that after close we can no longer read - stream.close(); - try { - stream.read(); - fail("Should have caught IOException"); - } catch (IOException ignored) { - // as expected - } - } + DocumentInputStream stream = new NDocumentInputStream(_workbook_n); + int remaining = _workbook_size; + + // Try and read each byte in turn + for (int j = 0; j < _workbook_size; j++) { + int b = stream.read(); + assertTrue("checking sign of " + j, b >= 0); + assertEquals("validating byte " + j, _workbook_data[j], + (byte) b); + remaining--; + assertEquals("checking remaining after reading byte " + j, + remaining, available(stream)); + } + + // Ensure we fell off the end + assertEquals(-1, stream.read()); + + // Check that after close we can no longer read + stream.close(); + stream.read(); } /** * Test buffered read */ + @SuppressWarnings("ResultOfMethodCallIgnored") @Test public void testBufferRead() throws IOException { - DocumentInputStream[] streams = new DocumentInputStream[] { - new DocumentInputStream(_workbook_o), - new NDocumentInputStream(_workbook_n) - }; - for(DocumentInputStream stream : streams) { - // Need to give a byte array to read - try { - stream.read(null); - fail("Should have caught NullPointerException"); - } catch (NullPointerException ignored) { - // as expected - } - - // test reading zero length buffer - assertEquals(0, stream.read(new byte[ 0 ])); - assertEquals(_workbook_size, available(stream)); - byte[] buffer = new byte[ _buffer_size ]; - int offset = 0; - - while (available(stream) >= buffer.length) - { - assertEquals(_buffer_size, stream.read(buffer)); - for (byte element : buffer) { + DocumentInputStream stream = new NDocumentInputStream(_workbook_n); + // Need to give a byte array to read + try { + stream.read(null); + fail("Should have caught NullPointerException"); + } catch (NullPointerException ignored) { + // as expected + } + + // test reading zero length buffer + assertEquals(0, stream.read(new byte[0])); + assertEquals(_workbook_size, available(stream)); + byte[] buffer = new byte[_buffer_size]; + int offset = 0; + + while (available(stream) >= buffer.length) { + assertEquals(_buffer_size, stream.read(buffer)); + for (byte element : buffer) { assertEquals("in main loop, byte " + offset, - _workbook_data[ offset ], element); + _workbook_data[offset], element); offset++; - } - assertEquals("offset " + offset, _workbook_size - offset, - available(stream)); - } - assertEquals(_workbook_size % _buffer_size, available(stream)); - Arrays.fill(buffer, ( byte ) 0); - int count = stream.read(buffer); - - assertEquals(_workbook_size % _buffer_size, count); - for (int j = 0; j < count; j++) - { - assertEquals("past main loop, byte " + offset, - _workbook_data[ offset ], buffer[ j ]); - offset++; - } - assertEquals(_workbook_size, offset); - for (int j = count; j < buffer.length; j++) - { - assertEquals("checking remainder, byte " + j, 0, buffer[ j ]); - } - assertEquals(-1, stream.read(buffer)); - stream.close(); - try { - stream.read(buffer); - fail("Should have caught IOException"); - } catch (IOException ignored) { - // as expected - } - } + } + assertEquals("offset " + offset, _workbook_size - offset, + available(stream)); + } + assertEquals(_workbook_size % _buffer_size, available(stream)); + Arrays.fill(buffer, (byte) 0); + int count = stream.read(buffer); + + assertEquals(_workbook_size % _buffer_size, count); + for (int j = 0; j < count; j++) { + assertEquals("past main loop, byte " + offset, + _workbook_data[offset], buffer[j]); + offset++; + } + assertEquals(_workbook_size, offset); + for (int j = count; j < buffer.length; j++) { + assertEquals("checking remainder, byte " + j, 0, buffer[j]); + } + assertEquals(-1, stream.read(buffer)); + stream.close(); + try { + stream.read(buffer); + fail("Should have caught IOException"); + } catch (IOException ignored) { + // as expected + } } /** * Test complex buffered read */ + @SuppressWarnings("ResultOfMethodCallIgnored") @Test public void testComplexBufferRead() throws IOException { - DocumentInputStream[] streams = new DocumentInputStream[] { - new DocumentInputStream(_workbook_o), - new NDocumentInputStream(_workbook_n) - }; - for(DocumentInputStream stream : streams) { - try { - stream.read(null, 0, 1); - fail("Should have caught NullPointerException"); - } catch (IllegalArgumentException ignored) { - // as expected - } - - // test illegal offsets and lengths - try { - stream.read(new byte[ 5 ], -4, 0); - fail("Should have caught IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException ignored) { - // as expected - } - try { - stream.read(new byte[ 5 ], 0, -4); - fail("Should have caught IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException ignored) { - // as expected - } - try { - stream.read(new byte[ 5 ], 0, 6); - fail("Should have caught IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException ignored) { - // as expected - } - - // test reading zero - assertEquals(0, stream.read(new byte[ 5 ], 0, 0)); - assertEquals(_workbook_size, available(stream)); - byte[] buffer = new byte[ _workbook_size ]; - int offset = 0; - - while (available(stream) >= _buffer_size) - { - Arrays.fill(buffer, ( byte ) 0); - assertEquals(_buffer_size, - stream.read(buffer, offset, _buffer_size)); - for (int j = 0; j < offset; j++) - { - assertEquals("checking byte " + j, 0, buffer[ j ]); - } - for (int j = offset; j < (offset + _buffer_size); j++) - { - assertEquals("checking byte " + j, _workbook_data[ j ], - buffer[ j ]); - } - for (int j = offset + _buffer_size; j < buffer.length; j++) - { - assertEquals("checking byte " + j, 0, buffer[ j ]); - } - offset += _buffer_size; - assertEquals("offset " + offset, _workbook_size - offset, - available(stream)); - } - assertEquals(_workbook_size % _buffer_size, available(stream)); - Arrays.fill(buffer, ( byte ) 0); - int count = stream.read(buffer, offset, + DocumentInputStream stream = new NDocumentInputStream(_workbook_n); + try { + stream.read(null, 0, 1); + fail("Should have caught NullPointerException"); + } catch (IllegalArgumentException ignored) { + // as expected + } + + // test illegal offsets and lengths + try { + stream.read(new byte[5], -4, 0); + fail("Should have caught IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException ignored) { + // as expected + } + try { + stream.read(new byte[5], 0, -4); + fail("Should have caught IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException ignored) { + // as expected + } + try { + stream.read(new byte[5], 0, 6); + fail("Should have caught IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException ignored) { + // as expected + } + + // test reading zero + assertEquals(0, stream.read(new byte[5], 0, 0)); + assertEquals(_workbook_size, available(stream)); + byte[] buffer = new byte[_workbook_size]; + int offset = 0; + + while (available(stream) >= _buffer_size) { + Arrays.fill(buffer, (byte) 0); + assertEquals(_buffer_size, + stream.read(buffer, offset, _buffer_size)); + for (int j = 0; j < offset; j++) { + assertEquals("checking byte " + j, 0, buffer[j]); + } + for (int j = offset; j < (offset + _buffer_size); j++) { + assertEquals("checking byte " + j, _workbook_data[j], + buffer[j]); + } + for (int j = offset + _buffer_size; j < buffer.length; j++) { + assertEquals("checking byte " + j, 0, buffer[j]); + } + offset += _buffer_size; + assertEquals("offset " + offset, _workbook_size - offset, + available(stream)); + } + assertEquals(_workbook_size % _buffer_size, available(stream)); + Arrays.fill(buffer, (byte) 0); + int count = stream.read(buffer, offset, _workbook_size % _buffer_size); - assertEquals(_workbook_size % _buffer_size, count); - for (int j = 0; j < offset; j++) - { - assertEquals("checking byte " + j, 0, buffer[ j ]); - } - for (int j = offset; j < buffer.length; j++) - { - assertEquals("checking byte " + j, _workbook_data[ j ], - buffer[ j ]); - } - assertEquals(_workbook_size, offset + count); - for (int j = count; j < offset; j++) - { - assertEquals("byte " + j, 0, buffer[ j ]); - } - - assertEquals(-1, stream.read(buffer, 0, 1)); - stream.close(); - try { - stream.read(buffer, 0, 1); - fail("Should have caught IOException"); - } catch (IOException ignored) { - // as expected - } - } + assertEquals(_workbook_size % _buffer_size, count); + for (int j = 0; j < offset; j++) { + assertEquals("checking byte " + j, 0, buffer[j]); + } + for (int j = offset; j < buffer.length; j++) { + assertEquals("checking byte " + j, _workbook_data[j], + buffer[j]); + } + assertEquals(_workbook_size, offset + count); + for (int j = count; j < offset; j++) { + assertEquals("byte " + j, 0, buffer[j]); + } + + assertEquals(-1, stream.read(buffer, 0, 1)); + stream.close(); + try { + stream.read(buffer, 0, 1); + fail("Should have caught IOException"); + } catch (IOException ignored) { + // as expected + } } /** @@ -488,82 +407,67 @@ public final class TestDocumentInputStream { */ @Test public void testSkip() throws IOException { - DocumentInputStream[] streams = new DocumentInputStream[] { - new DocumentInputStream(_workbook_o), - new NDocumentInputStream(_workbook_n) - }; - for(DocumentInputStream stream : streams) { - assertEquals(_workbook_size, available(stream)); - int count = available(stream); - - while (available(stream) >= _buffer_size) { - assertEquals(_buffer_size, stream.skip(_buffer_size)); - count -= _buffer_size; - assertEquals(count, available(stream)); - } - assertEquals(_workbook_size % _buffer_size, + DocumentInputStream stream = new NDocumentInputStream(_workbook_n); + assertEquals(_workbook_size, available(stream)); + int count = available(stream); + + while (available(stream) >= _buffer_size) { + assertEquals(_buffer_size, stream.skip(_buffer_size)); + count -= _buffer_size; + assertEquals(count, available(stream)); + } + assertEquals(_workbook_size % _buffer_size, stream.skip(_buffer_size)); - assertEquals(0, available(stream)); - stream.reset(); - assertEquals(_workbook_size, available(stream)); - assertEquals(_workbook_size, stream.skip(_workbook_size * 2)); - assertEquals(0, available(stream)); - stream.reset(); - assertEquals(_workbook_size, available(stream)); - assertEquals(_workbook_size, - stream.skip(2 + ( long ) Integer.MAX_VALUE)); - assertEquals(0, available(stream)); - } + assertEquals(0, available(stream)); + stream.reset(); + assertEquals(_workbook_size, available(stream)); + assertEquals(_workbook_size, stream.skip(_workbook_size * 2)); + assertEquals(0, available(stream)); + stream.reset(); + assertEquals(_workbook_size, available(stream)); + assertEquals(_workbook_size, + stream.skip(2 + (long) Integer.MAX_VALUE)); + assertEquals(0, available(stream)); } - + /** * Test that we can read files at multiple levels down the tree */ @Test public void testReadMultipleTreeLevels() throws Exception { - final POIDataSamples _samples = POIDataSamples.getPublisherInstance(); - File sample = _samples.getFile("Sample.pub"); - - DocumentInputStream stream; - - NPOIFSFileSystem npoifs = new NPOIFSFileSystem(sample); - try { - OPOIFSFileSystem opoifs = new OPOIFSFileSystem(new FileInputStream(sample)); - - // Ensure we have what we expect on the root - assertEquals(npoifs, npoifs.getRoot().getNFileSystem()); - assertEquals(npoifs, npoifs.getRoot().getFileSystem()); - assertEquals(null, npoifs.getRoot().getOFileSystem()); - assertEquals(null, opoifs.getRoot().getFileSystem()); - assertEquals(opoifs, opoifs.getRoot().getOFileSystem()); - assertEquals(null, opoifs.getRoot().getNFileSystem()); - - // Check inside - for(DirectoryNode root : new DirectoryNode[] { opoifs.getRoot(), npoifs.getRoot() }) { - // Top Level - Entry top = root.getEntry("Contents"); - assertEquals(true, top.isDocumentEntry()); - stream = root.createDocumentInputStream(top); - stream.read(); - - // One Level Down - DirectoryNode escher = (DirectoryNode)root.getEntry("Escher"); - Entry one = escher.getEntry("EscherStm"); - assertEquals(true, one.isDocumentEntry()); - stream = escher.createDocumentInputStream(one); - 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(); - } + final POIDataSamples _samples = POIDataSamples.getPublisherInstance(); + File sample = _samples.getFile("Sample.pub"); + + DocumentInputStream stream; + + try (NPOIFSFileSystem npoifs = new NPOIFSFileSystem(sample)) { + // Ensure we have what we expect on the root + assertEquals(npoifs, npoifs.getRoot().getNFileSystem()); + assertEquals(npoifs, npoifs.getRoot().getFileSystem()); + + // Check inside + DirectoryNode root = npoifs.getRoot(); + // Top Level + Entry top = root.getEntry("Contents"); + assertTrue(top.isDocumentEntry()); + stream = root.createDocumentInputStream(top); + assertNotEquals(-1, stream.read()); + + // One Level Down + DirectoryNode escher = (DirectoryNode) root.getEntry("Escher"); + Entry one = escher.getEntry("EscherStm"); + assertTrue(one.isDocumentEntry()); + stream = escher.createDocumentInputStream(one); + assertNotEquals(-1, stream.read()); + + // Two Levels Down + DirectoryNode quill = (DirectoryNode) root.getEntry("Quill"); + DirectoryNode quillSub = (DirectoryNode) quill.getEntry("QuillSub"); + Entry two = quillSub.getEntry("CONTENTS"); + assertTrue(two.isDocumentEntry()); + stream = quillSub.createDocumentInputStream(two); + assertNotEquals(-1, stream.read()); + } } @SuppressForbidden("just for testing") diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestDocumentNode.java b/src/testcases/org/apache/poi/poifs/filesystem/TestDocumentNode.java deleted file mode 100644 index 69d167793a..0000000000 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestDocumentNode.java +++ /dev/null @@ -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()); - } -} diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestFileSystemBugs.java b/src/testcases/org/apache/poi/poifs/filesystem/TestFileSystemBugs.java index ebf7fb1d09..3dda0dead8 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestFileSystemBugs.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestFileSystemBugs.java @@ -17,6 +17,9 @@ 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.ByteArrayOutputStream; import java.io.InputStream; @@ -26,20 +29,21 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import junit.framework.TestCase; - import org.apache.poi.POIDataSamples; +import org.junit.After; +import org.junit.Test; /** * Tests bugs across both POIFSFileSystem and NPOIFSFileSystem */ -public final class TestFileSystemBugs extends TestCase { - protected static POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); - protected static POIDataSamples _ssSamples = POIDataSamples.getSpreadSheetInstance(); - - protected List openedFSs; - @Override - protected void tearDown() throws Exception { +public final class TestFileSystemBugs { + private static POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); + private static POIDataSamples _ssSamples = POIDataSamples.getSpreadSheetInstance(); + + private List openedFSs; + + @After + public void tearDown() { if (openedFSs != null && !openedFSs.isEmpty()) { for (NPOIFSFileSystem fs : openedFSs) { try { @@ -51,65 +55,60 @@ public final class TestFileSystemBugs extends TestCase { } openedFSs = null; } - protected DirectoryNode[] openSample(String name, boolean oldFails) throws Exception { - return openSamples(new InputStream[] { - _samples.openResourceAsStream(name), - _samples.openResourceAsStream(name) - }, oldFails); + + private DirectoryNode openSample(String name) throws Exception { + try (InputStream inps = _samples.openResourceAsStream(name)) { + return openSample(inps); + } } - protected DirectoryNode[] openSSSample(String name, boolean oldFails) throws Exception { - return openSamples(new InputStream[] { - _ssSamples.openResourceAsStream(name), - _ssSamples.openResourceAsStream(name) - }, oldFails); + + @SuppressWarnings("SameParameterValue") + private DirectoryNode openSSSample(String name) throws Exception { + try (InputStream inps = _ssSamples.openResourceAsStream(name)) { + return openSample(inps); + } } - 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; + + private DirectoryNode openSample(InputStream inps) throws Exception { + NPOIFSFileSystem nfs = new NPOIFSFileSystem(inps); + if (openedFSs == null) { + openedFSs = new ArrayList<>(); } + openedFSs.add(nfs); - if (ofs == null) return new DirectoryNode[] { nfs.getRoot() }; - return new DirectoryNode[] { ofs.getRoot(), nfs.getRoot() }; + return nfs.getRoot(); } /** * Test that we can open files that come via Lotus notes. * These have a top level directory without a name.... */ + @Test public void testNotesOLE2Files() throws Exception { // Check the contents - for (DirectoryNode root : openSample("Notes.ole2", false)) { - assertEquals(1, root.getEntryCount()); + DirectoryNode root = openSample("Notes.ole2"); + assertEquals(1, root.getEntryCount()); - Entry entry = root.getEntries().next(); - assertTrue(entry.isDirectoryEntry()); - assertTrue(entry instanceof DirectoryEntry); + Entry entry = root.getEntries().next(); + assertTrue(entry.isDirectoryEntry()); + assertTrue(entry instanceof DirectoryEntry); - // The directory lacks a name! - DirectoryEntry dir = (DirectoryEntry)entry; - assertEquals("", dir.getName()); + // The directory lacks a name! + DirectoryEntry dir = (DirectoryEntry)entry; + assertEquals("", dir.getName()); - // Has two children - assertEquals(2, dir.getEntryCount()); + // Has two children + assertEquals(2, dir.getEntryCount()); - // Check them - Iterator it = dir.getEntries(); - entry = it.next(); - assertEquals(true, entry.isDocumentEntry()); - assertEquals(Ole10Native.OLE10_NATIVE, entry.getName()); + // Check them + Iterator it = dir.getEntries(); + entry = it.next(); + assertTrue(entry.isDocumentEntry()); + assertEquals(Ole10Native.OLE10_NATIVE, entry.getName()); - entry = it.next(); - assertEquals(true, entry.isDocumentEntry()); - assertEquals("\u0001CompObj", entry.getName()); - } + entry = it.next(); + assertTrue(entry.isDocumentEntry()); + assertEquals("\u0001CompObj", entry.getName()); } /** @@ -119,46 +118,39 @@ public final class TestFileSystemBugs extends TestCase { * Note - only works for NPOIFSFileSystem, POIFSFileSystem * can't cope with this level of corruption */ + @Test public void testCorruptedProperties() throws Exception { - for (DirectoryNode root : openSample("unknown_properties.msg", true)) { - assertEquals(42, root.getEntryCount()); - } + DirectoryNode root = openSample("unknown_properties.msg"); + assertEquals(42, root.getEntryCount()); } /** * With heavily nested documents, ensure we still re-write the same */ + @Test public void testHeavilyNestedReWrite() throws Exception { - for (DirectoryNode root : openSSSample("ex42570-20305.xls", false)) { - // Record the structure - Map entries = new HashMap<>(); - fetchSizes("/", root, entries); - - // Prepare to copy - DirectoryNode dest; - if (root.getNFileSystem() != null) { - dest = (new NPOIFSFileSystem()).getRoot(); - } else { - dest = (new OPOIFSFileSystem()).getRoot(); - } - - // Copy over - EntryUtils.copyNodes(root, dest); - - // Re-load, always as NPOIFS - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - if (root.getNFileSystem() != null) { - root.getNFileSystem().writeFilesystem(baos); - } else { - root.getOFileSystem().writeFilesystem(baos); - } - NPOIFSFileSystem read = new NPOIFSFileSystem( - new ByteArrayInputStream(baos.toByteArray())); - - // Check the structure matches - checkSizes("/", read.getRoot(), entries); - } + DirectoryNode root = openSSSample("ex42570-20305.xls"); + // Record the structure + Map entries = new HashMap<>(); + fetchSizes("/", root, entries); + + // Prepare to copy + DirectoryNode dest = new NPOIFSFileSystem().getRoot(); + + // Copy over + EntryUtils.copyNodes(root, dest); + + // Re-load, always as NPOIFS + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + root.getNFileSystem().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 entries) { for (Entry entry : dir) { if (entry instanceof DirectoryNode) { diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java index 1a199cb54c..3bb90d0989 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java @@ -17,6 +17,26 @@ 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.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.PropertySet; @@ -34,14 +54,6 @@ import org.junit.Assume; import org.junit.Ignore; 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 */ @@ -52,7 +64,7 @@ public final class TestNPOIFSFileSystem { * Returns test files with 512 byte and 4k block sizes, loaded * both from InputStreams and Files */ - protected NPOIFSFileSystem[] get512and4kFileAndInput() throws IOException { + private NPOIFSFileSystem[] get512and4kFileAndInput() throws IOException { NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); NPOIFSFileSystem fsC = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); @@ -60,7 +72,7 @@ public final class TestNPOIFSFileSystem { 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 foundXBAT = 0; 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 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); byte[] contents = new byte[doc.getSize()]; assertEquals(doc.getSize(), inp.read(contents)); @@ -85,21 +97,21 @@ public final class TestNPOIFSFileSystem { assertThat(expected, equalTo(contents)); } } - - protected static HeaderBlock writeOutAndReadHeader(NPOIFSFileSystem fs) throws IOException { + + private static HeaderBlock writeOutAndReadHeader(NPOIFSFileSystem fs) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); fs.writeFilesystem(baos); 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(); original.writeFilesystem(baos); 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"); try (OutputStream fout = new FileOutputStream(file)) { original.writeFilesystem(fout); @@ -179,7 +191,7 @@ public final class TestNPOIFSFileSystem { assertEquals("Image", prop.getName()); prop = pi.next(); assertEquals("Tags", prop.getName()); - assertEquals(false, pi.hasNext()); + assertFalse(pi.hasNext()); // Check the SBAT (Small Blocks FAT) was properly processed @@ -250,7 +262,7 @@ public final class TestNPOIFSFileSystem { assertEquals("Image", prop.getName()); prop = pi.next(); assertEquals("Tags", prop.getName()); - assertEquals(false, pi.hasNext()); + assertFalse(pi.hasNext()); // 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")); // Our first BAT block has spares - assertEquals(true, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + assertTrue(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); // First free one is 100 assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100)); @@ -463,7 +475,7 @@ public final class TestNPOIFSFileSystem { } // 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 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 - assertEquals(false, fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); try { - assertEquals(false, fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); fail("Should only be one BAT"); } catch(IndexOutOfBoundsException e) { // expected here @@ -483,9 +495,9 @@ public final class TestNPOIFSFileSystem { // Now ask for a free one, will need to extend the file assertEquals(129, fs1.getFreeBlock()); - - assertEquals(false, fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); - assertEquals(true, fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); + + assertFalse(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + assertTrue(fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(128)); assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(129)); @@ -502,10 +514,10 @@ public final class TestNPOIFSFileSystem { 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 { - assertEquals(false, fs1.getBATBlockAndIndex(109*128).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(109 * 128).getBlock().hasFreeSectors()); fail("Should only be 109 BATs"); } catch(IndexOutOfBoundsException e) { // expected here @@ -525,10 +537,10 @@ public final class TestNPOIFSFileSystem { free = fs1.getFreeBlock(); assertTrue("Had: " + free, free > 0); - assertEquals(false, fs1.getBATBlockAndIndex(109*128-1).getBlock().hasFreeSectors()); - assertEquals(true, fs1.getBATBlockAndIndex(110*128-1).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors()); + assertTrue(fs1.getBATBlockAndIndex(110 * 128 - 1).getBlock().hasFreeSectors()); try { - assertEquals(false, fs1.getBATBlockAndIndex(110*128).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(110 * 128).getBlock().hasFreeSectors()); fail("Should only be 110 BATs"); } catch(IndexOutOfBoundsException e) { // expected here @@ -552,9 +564,9 @@ public final class TestNPOIFSFileSystem { } // 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 { - assertEquals(false, fs1.getBATBlockAndIndex(236*128).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(236 * 128).getBlock().hasFreeSectors()); fail("Should only be 236 BATs"); } catch(IndexOutOfBoundsException e) { // expected here @@ -566,10 +578,10 @@ public final class TestNPOIFSFileSystem { free = fs1.getFreeBlock(); assertTrue("Had: " + free, free > 0); - assertEquals(false, fs1.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors()); - assertEquals(true, fs1.getBATBlockAndIndex(237*128-1).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors()); + assertTrue(fs1.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors()); try { - assertEquals(false, fs1.getBATBlockAndIndex(237*128).getBlock().hasFreeSectors()); + assertFalse(fs1.getBATBlockAndIndex(237 * 128).getBlock().hasFreeSectors()); fail("Should only be 237 BATs"); } catch(IndexOutOfBoundsException e) { // expected here @@ -590,10 +602,10 @@ public final class TestNPOIFSFileSystem { // Check that it is seen correctly assertBATCount(fs2, 237, 2); - assertEquals(false, fs2.getBATBlockAndIndex(236*128-1).getBlock().hasFreeSectors()); - assertEquals(true, fs2.getBATBlockAndIndex(237*128-1).getBlock().hasFreeSectors()); + assertFalse(fs2.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors()); + assertTrue(fs2.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors()); try { - assertEquals(false, fs2.getBATBlockAndIndex(237*128).getBlock().hasFreeSectors()); + assertFalse(fs2.getBATBlockAndIndex(237 * 128).getBlock().hasFreeSectors()); fail("Should only be 237 BATs"); } catch(IndexOutOfBoundsException e) { // expected here @@ -620,12 +632,12 @@ public final class TestNPOIFSFileSystem { Entry si = root.getEntry("\u0005SummaryInformation"); Entry image = root.getEntry("Image"); Entry tags = root.getEntry("Tags"); - - assertEquals(false, thumbnail.isDirectoryEntry()); - assertEquals(false, dsi.isDirectoryEntry()); - assertEquals(false, si.isDirectoryEntry()); - assertEquals(true, image.isDirectoryEntry()); - assertEquals(false, tags.isDirectoryEntry()); + + assertFalse(thumbnail.isDirectoryEntry()); + assertFalse(dsi.isDirectoryEntry()); + assertFalse(si.isDirectoryEntry()); + assertTrue(image.isDirectoryEntry()); + assertFalse(tags.isDirectoryEntry()); // Check via the iterator Iterator it = root.getEntries(); @@ -652,8 +664,8 @@ public final class TestNPOIFSFileSystem { for(NPOIFSFileSystem fs : get512and4kFileAndInput()) { DirectoryEntry root = fs.getRoot(); Entry si = root.getEntry("\u0005SummaryInformation"); - - assertEquals(true, si.isDocumentEntry()); + + assertTrue(si.isDocumentEntry()); DocumentNode doc = (DocumentNode)si; // Check we can read it @@ -665,9 +677,9 @@ public final class TestNPOIFSFileSystem { SummaryInformation inf = (SummaryInformation)ps; // Check some bits in it - assertEquals(null, inf.getApplicationName()); - assertEquals(null, inf.getAuthor()); - assertEquals(null, inf.getSubject()); + assertNull(inf.getApplicationName()); + assertNull(inf.getAuthor()); + assertNull(inf.getSubject()); assertEquals(131333, inf.getOSVersion()); // Finish with this one @@ -676,7 +688,7 @@ public final class TestNPOIFSFileSystem { // Try the other summary information si = root.getEntry("\u0005DocumentSummaryInformation"); - assertEquals(true, si.isDocumentEntry()); + assertTrue(si.isDocumentEntry()); doc = (DocumentNode)si; assertContentsMatches(null, doc); @@ -1541,7 +1553,7 @@ public final class TestNPOIFSFileSystem { DirectoryEntry vbaProj = (DirectoryEntry)src.getRoot().getEntry("_VBA_PROJECT_CUR"); assertEquals(3, vbaProj.getEntryCount()); // Can't delete yet, has stuff - assertEquals(false, vbaProj.delete()); + assertFalse(vbaProj.delete()); // Recursively delete _recursiveDeletee(vbaProj); @@ -1554,7 +1566,7 @@ public final class TestNPOIFSFileSystem { } private void _recursiveDeletee(Entry entry) throws IOException { if (entry.isDocumentEntry()) { - assertEquals(true, entry.delete()); + assertTrue(entry.delete()); return; } @@ -1564,7 +1576,7 @@ public final class TestNPOIFSFileSystem { Entry ce = dir.getEntry(name); _recursiveDeletee(ce); } - assertEquals(true, dir.delete()); + assertTrue(dir.delete()); } @SuppressWarnings("unused") private int _countChildren(DirectoryProperty p) { @@ -1677,24 +1689,24 @@ public final class TestNPOIFSFileSystem { fs.createDocument(new DummyDataInputStream(s2gb), "Big"); } - protected static class DummyDataInputStream extends InputStream { - protected final long maxSize; - protected long size; - public DummyDataInputStream(long maxSize) { + private static final class DummyDataInputStream extends InputStream { + private final long maxSize; + private long size; + private DummyDataInputStream(long maxSize) { this.maxSize = maxSize; this.size = 0; } - public int read() throws IOException { + public int read() { if (size >= maxSize) return -1; size++; return (int)(size % 128); } - public int read(byte[] b) throws IOException { + public int read(byte[] b) { 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; int sz = (int)Math.min(len, maxSize-size); for (int i=0; i 0) System.out.println(); } } @@ -1754,7 +1765,6 @@ public final class TestNPOIFSFileSystem { assertTrue(file.delete()); if (i % 10 == 0) System.out.print("."); - if (i % 800 == 0 && i > 0) System.out.println(); } } diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java b/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java index d1ae24851c..3c3f6b83aa 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java @@ -17,14 +17,16 @@ 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.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; -import junit.framework.TestCase; - import org.apache.poi.POIDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples; 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.RawDataBlockList; 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 */ -public final class TestPOIFSFileSystem extends TestCase { +public final class TestPOIFSFileSystem { private final POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); /** * Mock exception used to ensure correct error handling */ private static final class MyEx extends RuntimeException { - public MyEx() { + MyEx() { // no fields to initialise } } @@ -60,7 +65,7 @@ public final class TestPOIFSFileSystem extends TestCase { private int _currentIx; private boolean _isClosed; - public TestIS(InputStream is, int failIndex) { + TestIS(InputStream is, int failIndex) { _is = is; _failIndex = failIndex; _currentIx = 0; @@ -93,7 +98,7 @@ public final class TestPOIFSFileSystem extends TestCase { _isClosed = true; _is.close(); } - public boolean isClosed() { + boolean 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). * POIFSFileSystem was not closing the input stream. */ - public void testAlwaysClose() { + @Test + public void testAlwaysClose() throws IOException { TestIS testIS; // Normal case - read until EOF and close testIS = new TestIS(openSampleStream("13224.xls"), -1); - try { - new OPOIFSFileSystem(testIS); - } catch (IOException e) { - throw new RuntimeException(e); + try (NPOIFSFileSystem ignored = new NPOIFSFileSystem(testIS)){ + assertTrue("input stream was not closed", testIS.isClosed()); } - assertTrue("input stream was not closed", testIS.isClosed()); // intended to crash after reading 10000 bytes testIS = new TestIS(openSampleStream("13224.xls"), 10000); - try { - new OPOIFSFileSystem(testIS); + try (NPOIFSFileSystem ignored = new NPOIFSFileSystem(testIS)){ fail("ex should have been thrown"); - } catch (IOException e) { - throw new RuntimeException(e); } catch (MyEx e) { // 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 * POIFS, since it seems to be slight wrong */ + @Test public void testShortLastBlock() throws Exception { String[] files = new String[] { "ShortLastBlock.qwp", "ShortLastBlock.wps" @@ -145,7 +148,7 @@ public final class TestPOIFSFileSystem extends TestCase { for (String file : files) { // Open the file up - OPOIFSFileSystem fs = new OPOIFSFileSystem( + NPOIFSFileSystem fs = new NPOIFSFileSystem( _samples.openResourceAsStream(file) ); @@ -156,26 +159,24 @@ public final class TestPOIFSFileSystem extends TestCase { // Check sizes } } - + + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + /** * Check that we do the right thing when the list of which * sectors are BAT blocks points off the list of * sectors that exist in the file. */ + @Test public void testFATandDIFATsectors() throws Exception { // Open the file up - try { - InputStream stream = _samples.openResourceAsStream("ReferencesInvalidSectors.mpp"); - try { - new OPOIFSFileSystem(stream); - 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")); - } + expectedEx.expect(IndexOutOfBoundsException.class); + expectedEx.expectMessage("Block 1148 not found"); + try (InputStream stream = _samples.openResourceAsStream("ReferencesInvalidSectors.mpp")) { + new NPOIFSFileSystem(stream); + fail("File is corrupt and shouldn't have been opened"); + } } /** @@ -184,9 +185,10 @@ public final class TestPOIFSFileSystem extends TestCase { * 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. */ + @Test public void testBATandXBAT() throws Exception { byte[] hugeStream = new byte[8*1024*1024]; - OPOIFSFileSystem fs = new OPOIFSFileSystem(); + NPOIFSFileSystem fs = new NPOIFSFileSystem(); fs.getRoot().createDocument( "BIG", new ByteArrayInputStream(hugeStream) ); @@ -229,8 +231,7 @@ public final class TestPOIFSFileSystem extends TestCase { assertEquals(fsData.length / 512, blockList.blockCount() + 1); // Header not counted // Now load it and check - fs = null; - fs = new OPOIFSFileSystem( + fs = new NPOIFSFileSystem( new ByteArrayInputStream(fsData) ); @@ -244,41 +245,39 @@ public final class TestPOIFSFileSystem extends TestCase { * Most OLE2 files use 512byte blocks. However, a small number * use 4k blocks. Check that we can open these. */ + @Test public void test4KBlocks() throws Exception { POIDataSamples _samples = POIDataSamples.getPOIFSInstance(); - InputStream inp = _samples.openResourceAsStream("BlockSize4096.zvi"); - try { - // First up, check that we can process the header properly - HeaderBlock header_block = new HeaderBlock(inp); - POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize(); - assertEquals(4096, bigBlockSize.getBigBlockSize()); + try (InputStream inp = _samples.openResourceAsStream("BlockSize4096.zvi")) { + // First up, check that we can process the header properly + HeaderBlock header_block = new HeaderBlock(inp); + POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize(); + assertEquals(4096, bigBlockSize.getBigBlockSize()); - // Check the fat info looks sane - assertEquals(1, header_block.getBATArray().length); - assertEquals(1, header_block.getBATCount()); - assertEquals(0, header_block.getXBATCount()); + // Check the fat info looks sane + assertEquals(1, header_block.getBATArray().length); + assertEquals(1, header_block.getBATCount()); + assertEquals(0, header_block.getXBATCount()); - // Now check we can get the basic fat - RawDataBlockList data_blocks = new RawDataBlockList(inp, - bigBlockSize); - assertEquals(15, data_blocks.blockCount()); + // Now check we can get the basic fat + RawDataBlockList data_blocks = new RawDataBlockList(inp, + bigBlockSize); + assertEquals(15, data_blocks.blockCount()); - // Now try and open properly - OPOIFSFileSystem fs = new OPOIFSFileSystem( - _samples.openResourceAsStream("BlockSize4096.zvi")); - assertTrue(fs.getRoot().getEntryCount() > 3); + // Now try and open properly + NPOIFSFileSystem fs = new NPOIFSFileSystem( + _samples.openResourceAsStream("BlockSize4096.zvi")); + assertTrue(fs.getRoot().getEntryCount() > 3); - // Check we can get at all the contents - checkAllDirectoryContents(fs.getRoot()); + // Check we can get at all the contents + checkAllDirectoryContents(fs.getRoot()); - // Finally, check we can do a similar 512byte one too - fs = new OPOIFSFileSystem( - _samples.openResourceAsStream("BlockSize512.zvi")); - assertTrue(fs.getRoot().getEntryCount() > 3); - checkAllDirectoryContents(fs.getRoot()); - } finally { - inp.close(); - } + // Finally, check we can do a similar 512byte one too + fs = new NPOIFSFileSystem( + _samples.openResourceAsStream("BlockSize512.zvi")); + assertTrue(fs.getRoot().getEntryCount() > 3); + checkAllDirectoryContents(fs.getRoot()); + } } private void checkAllDirectoryContents(DirectoryEntry dir) throws IOException { for(Entry entry : dir) { @@ -293,6 +292,7 @@ public final class TestPOIFSFileSystem extends TestCase { } } + @SuppressWarnings("SameParameterValue") private static InputStream openSampleStream(String sampleFileName) { return HSSFTestDataSamples.openSampleFileStream(sampleFileName); } diff --git a/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java b/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java index 582b3af78e..4189215720 100644 --- a/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java +++ b/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java @@ -20,7 +20,7 @@ package org.apache.poi.poifs.storage; import org.junit.runner.RunWith; import org.junit.runners.Suite; /** - * Tests for org.apache.poi.poifs.storage
+ * Tests for org.apache.poi.poifs.storage */ @RunWith(Suite.class) @Suite.SuiteClasses({ @@ -33,11 +33,7 @@ import org.junit.runners.Suite; TestHeaderBlockWriting.class, TestPropertyBlock.class, TestRawDataBlock.class, - TestRawDataBlockList.class, - TestSmallBlockTableReader.class, - TestSmallBlockTableWriter.class, - TestSmallDocumentBlock.class, - TestSmallDocumentBlockList.class + TestRawDataBlockList.class }) public class AllPOIFSStorageTests { } diff --git a/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java b/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java index 6a249afc1a..233d2b0dd9 100644 --- a/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java +++ b/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java @@ -17,196 +17,58 @@ 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.IOException; import java.io.InputStream; import java.util.Arrays; import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.util.HexRead; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianConsts; +import org.junit.Test; /** * Class to test BlockAllocationTableReader functionality - * - * @author Marc Johnson */ -public final class TestBlockAllocationTableReader extends TestCase { +public class TestBlockAllocationTableReader { /** * Test small block allocation table constructor */ + @Test public void testSmallBATConstructor() throws IOException { // need to create an array of raw blocks containing the SBAT, // and a small document block list - String[] sbat_data = { - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 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", - }; + final String sbat_data = "H4sIAAAAAAAAAPv/nzjwj4ZYiYGBAZfcKKAtAAC/sexrAAIAAA=="; - RawDataBlock[] sbats = { new RawDataBlock(makeDataStream(sbat_data)) }; - - 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", - "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", - "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 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[] sbats = { new RawDataBlock(new ByteArrayInputStream(RawDataUtil.decompress(sbat_data))) }; - RawDataBlock[] sbts = new RawDataBlock[7]; - InputStream sbt_input = makeDataStream(sbt_data); + final String sbt_data = + "H4sIAAAAAAAAAONg0GDISsxNLdYNNTc3Mrc00tUwNNP1Ty7RNTIwMHQAsk0MdY2NNfWiXNwYsAB2MNmg/sgBmyxhQB395AMm" + + "BkaK9HNQaD83hfqZKXY/E4OCIQcDK0NwYllqCgeDOEOwnkdocLCjp5+Co4KLa5iCv5tbkEKoNwfQrUhJA6TFVM9Yz4gy94OM" + + "Aac/svVTaj8zg7tTAAX6ZRk0HDWRAkahJF8BiUtQPyMDITX4ABMFegeDfsrjjzLAxCBBoX7KwED7n/LwG2j7KSv/Bt79A2s/" + + "NdzPQUWaVDDQ/h/o+meop5+hrx9ng4ku9jOhYVIBM4X2j4KhDQAtwD4rAA4AAA=="; - for (int j = 0; j < 7; j++) { - sbts[j] = new RawDataBlock(sbt_input); + InputStream sbt_input = new ByteArrayInputStream(RawDataUtil.decompress(sbt_data)); + + BlockListImpl small_blocks = new RawDataBlockList(sbt_input, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); + int blockCount = small_blocks.blockCount(); + ListManagedBlock[] lmb = new ListManagedBlock[7*blockCount]; + for (int i=0; i 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()); - } -} diff --git a/src/testcases/org/apache/poi/poifs/storage/TestSmallDocumentBlock.java b/src/testcases/org/apache/poi/poifs/storage/TestSmallDocumentBlock.java deleted file mode 100644 index c637e79706..0000000000 --- a/src/testcases/org/apache/poi/poifs/storage/TestSmallDocumentBlock.java +++ /dev/null @@ -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 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 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 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++; - } - } - } -} diff --git a/src/testcases/org/apache/poi/poifs/storage/TestSmallDocumentBlockList.java b/src/testcases/org/apache/poi/poifs/storage/TestSmallDocumentBlockList.java deleted file mode 100644 index 5301214e91..0000000000 --- a/src/testcases/org/apache/poi/poifs/storage/TestSmallDocumentBlockList.java +++ /dev/null @@ -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!! - } - } -}