Copied: poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java (from r1839708, poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java) URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java?p2=poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java&p1=poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java&r1=1839708&r2=1839709&rev=1839709&view=diff ============================================================================== --- poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java (original) +++ poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java Fri Aug 31 00:25:50 2018 @@ -17,41 +17,68 @@ package org.apache.poi.poifs.filesystem; -import static org.apache.poi.poifs.filesystem.TestNPOIFSFileSystem.writeOutAndReadBack; +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 junit.framework.TestCase; - import org.apache.poi.POIDataSamples; +import org.apache.poi.hpsf.DocumentSummaryInformation; +import org.apache.poi.hpsf.PropertySet; +import org.apache.poi.hpsf.PropertySetFactory; +import org.apache.poi.hpsf.SummaryInformation; 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.property.RootProperty; import org.apache.poi.poifs.storage.BATBlock; +import org.apache.poi.poifs.storage.HeaderBlock; +import org.apache.poi.util.IOUtils; +import org.apache.poi.util.TempFile; +import org.junit.Assume; +import org.junit.Ignore; +import org.junit.Test; /** - * Tests {@link NPOIFSStream} + * Tests {@link POIFSStream} */ -@SuppressWarnings("resource") -public final class TestNPOIFSStream extends TestCase { +public final class TestPOIFSStream { private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance(); /** * Read a single block stream */ + @Test public void testReadTinyStream() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); // 98 is actually the last block in a two block stream... - NPOIFSStream stream = new NPOIFSStream(fs, 98); + POIFSStream stream = new POIFSStream(fs, 98); Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b = i.next(); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); // Check the contents assertEquals((byte)0x81, b.get()); @@ -69,22 +96,23 @@ public final class TestNPOIFSStream exte /** * Read a stream with only two blocks in it */ + @Test public void testReadShortStream() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); // 97 -> 98 -> end - NPOIFSStream stream = new NPOIFSStream(fs, 97); + POIFSStream stream = new POIFSStream(fs, 97); Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b97 = i.next(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b98 = i.next(); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); // Check the contents of the 1st block assertEquals((byte)0x01, b97.get()); @@ -112,15 +140,16 @@ public final class TestNPOIFSStream exte /** * Read a stream with many blocks */ + @Test public void testReadLongerStream() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); ByteBuffer b0 = null; ByteBuffer b1 = null; ByteBuffer b22 = null; // The stream at 0 has 23 blocks in it - NPOIFSStream stream = new NPOIFSStream(fs, 0); + POIFSStream stream = new POIFSStream(fs, 0); Iterator<ByteBuffer> i = stream.getBlockIterator(); int count = 0; while(i.hasNext()) { @@ -168,25 +197,26 @@ public final class TestNPOIFSStream exte /** * Read a stream with several blocks in a 4096 byte block file */ + @Test public void testReadStream4096() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); // 0 -> 1 -> 2 -> end - NPOIFSStream stream = new NPOIFSStream(fs, 0); + POIFSStream stream = new POIFSStream(fs, 0); Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b0 = i.next(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b1 = i.next(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b2 = i.next(); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); // Check the contents of the 1st block assertEquals((byte)0x9E, b0.get()); @@ -224,8 +254,9 @@ public final class TestNPOIFSStream exte /** * Craft a nasty file with a loop, and ensure we don't get stuck */ + @Test public void testReadFailsOnLoop() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); // Hack the FAT so that it goes 0->1->2->0 fs.setNextBlock(0, 1); @@ -233,21 +264,21 @@ public final class TestNPOIFSStream exte fs.setNextBlock(2, 0); // Now try to read - NPOIFSStream stream = new NPOIFSStream(fs, 0); + POIFSStream stream = new POIFSStream(fs, 0); Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); // 1st read works i.next(); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); // 2nd read works i.next(); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); // 3rd read works i.next(); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); // 4th read blows up as it loops back to 0 try { @@ -256,7 +287,7 @@ public final class TestNPOIFSStream exte } catch(RuntimeException e) { // Good, it was detected } - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); fs.close(); } @@ -265,25 +296,26 @@ public final class TestNPOIFSStream exte * Tests that we can load some streams that are * stored in the mini stream. */ + @Test public void testReadMiniStreams() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - NPOIFSMiniStore ministore = fs.getMiniStore(); + POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + POIFSMiniStore ministore = fs.getMiniStore(); // 178 -> 179 -> 180 -> end - NPOIFSStream stream = new NPOIFSStream(ministore, 178); + POIFSStream stream = new POIFSStream(ministore, 178); Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b178 = i.next(); - assertEquals(true, i.hasNext()); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b179 = i.next(); - assertEquals(true, i.hasNext()); + assertTrue(i.hasNext()); ByteBuffer b180 = i.next(); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); - assertEquals(false, i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); + assertFalse(i.hasNext()); // Check the contents of the 1st block assertEquals((byte)0xfe, b178.get()); @@ -321,8 +353,9 @@ public final class TestNPOIFSStream exte /** * Writing the same amount of data as before */ + @Test public void testReplaceStream() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); byte[] data = new byte[512]; for(int i=0; i<data.length; i++) { @@ -330,14 +363,14 @@ public final class TestNPOIFSStream exte } // 98 is actually the last block in a two block stream... - NPOIFSStream stream = new NPOIFSStream(fs, 98); + POIFSStream stream = new POIFSStream(fs, 98); stream.updateContents(data); // Check the reading of blocks Iterator<ByteBuffer> it = stream.getBlockIterator(); - assertEquals(true, it.hasNext()); + assertTrue(it.hasNext()); ByteBuffer b = it.next(); - assertEquals(false, it.hasNext()); + assertFalse(it.hasNext()); // Now check the contents data = new byte[512]; @@ -354,94 +387,97 @@ public final class TestNPOIFSStream exte * Writes less data than before, some blocks will need * to be freed */ + @Test public void testReplaceStreamWithLess() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - - byte[] data = new byte[512]; - for(int i=0; i<data.length; i++) { - data[i] = (byte)(i%256); - } - - // 97 -> 98 -> end - assertEquals(98, fs.getNextBlock(97)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); - - // Create a 2 block stream, will become a 1 block one - NPOIFSStream stream = new NPOIFSStream(fs, 97); - stream.updateContents(data); - - // 97 should now be the end, and 98 free - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(97)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(98)); - - // Check the reading of blocks - Iterator<ByteBuffer> it = stream.getBlockIterator(); - assertEquals(true, it.hasNext()); - ByteBuffer b = it.next(); - assertEquals(false, it.hasNext()); - - // Now check the contents - data = new byte[512]; - b.get(data); - for(int i=0; i<data.length; i++) { - byte exp = (byte)(i%256); - assertEquals(exp, data[i]); + try (InputStream is = _inst.openResourceAsStream("BlockSize512.zvi"); + POIFSFileSystem fs = new POIFSFileSystem(is)) { + + byte[] data = new byte[512]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (i % 256); + } + + // 97 -> 98 -> end + assertEquals(98, fs.getNextBlock(97)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); + + // Create a 2 block stream, will become a 1 block one + POIFSStream stream = new POIFSStream(fs, 97); + stream.updateContents(data); + + // 97 should now be the end, and 98 free + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(97)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(98)); + + // Check the reading of blocks + Iterator<ByteBuffer> it = stream.getBlockIterator(); + assertTrue(it.hasNext()); + ByteBuffer b = it.next(); + assertFalse(it.hasNext()); + + // Now check the contents + data = new byte[512]; + b.get(data); + for (int i = 0; i < data.length; i++) { + byte exp = (byte) (i % 256); + assertEquals(exp, data[i]); + } } - - fs.close(); } /** * Writes more data than before, new blocks will be needed */ + @Test public void testReplaceStreamWithMore() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - - byte[] data = new byte[512*3]; - for(int i=0; i<data.length; i++) { - data[i] = (byte)(i%256); - } - - // 97 -> 98 -> end - assertEquals(98, fs.getNextBlock(97)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); - - // 100 is our first free one - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100)); - - // Create a 2 block stream, will become a 3 block one - NPOIFSStream stream = new NPOIFSStream(fs, 97); - stream.updateContents(data); - - // 97 -> 98 -> 100 -> end - assertEquals(98, fs.getNextBlock(97)); - assertEquals(100, fs.getNextBlock(98)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100)); - - // Check the reading of blocks - Iterator<ByteBuffer> it = stream.getBlockIterator(); - int count = 0; - while(it.hasNext()) { - ByteBuffer b = it.next(); - data = new byte[512]; - b.get(data); - for(int i=0; i<data.length; i++) { - byte exp = (byte)(i%256); - assertEquals(exp, data[i]); - } - count++; + try (InputStream is = _inst.openResourceAsStream("BlockSize512.zvi"); + POIFSFileSystem fs = new POIFSFileSystem(is)) { + + byte[] data = new byte[512 * 3]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (i % 256); + } + + // 97 -> 98 -> end + assertEquals(98, fs.getNextBlock(97)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); + + // 100 is our first free one + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100)); + + // Create a 2 block stream, will become a 3 block one + POIFSStream stream = new POIFSStream(fs, 97); + stream.updateContents(data); + + // 97 -> 98 -> 100 -> end + assertEquals(98, fs.getNextBlock(97)); + assertEquals(100, fs.getNextBlock(98)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100)); + + // Check the reading of blocks + Iterator<ByteBuffer> it = stream.getBlockIterator(); + int count = 0; + while (it.hasNext()) { + ByteBuffer b = it.next(); + data = new byte[512]; + b.get(data); + for (int i = 0; i < data.length; i++) { + byte exp = (byte) (i % 256); + assertEquals(exp, data[i]); + } + count++; + } + assertEquals(3, count); } - assertEquals(3, count); - - fs.close(); } /** * Writes to a new stream in the file */ + @Test public void testWriteNewStream() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); // 100 is our first free one assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); @@ -458,7 +494,7 @@ public final class TestNPOIFSStream exte data[i] = (byte)(i%256); } - NPOIFSStream stream = new NPOIFSStream(fs); + POIFSStream stream = new POIFSStream(fs); stream.updateContents(data); // Check it was allocated properly @@ -491,7 +527,7 @@ public final class TestNPOIFSStream exte data[i] = (byte)(i%256); } - stream = new NPOIFSStream(fs); + stream = new POIFSStream(fs); stream.updateContents(data); // Check it was allocated properly @@ -534,8 +570,9 @@ public final class TestNPOIFSStream exte * free blocks so new FAT segments will need to be allocated * to support this */ + @Test public void testWriteNewStreamExtraFATs() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); // Allocate almost all the blocks assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); @@ -545,7 +582,7 @@ public final class TestNPOIFSStream exte fs.setNextBlock(i, POIFSConstants.END_OF_CHAIN); } assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(127)); - assertEquals(true, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + assertTrue(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); // Write a 3 block stream @@ -553,12 +590,12 @@ public final class TestNPOIFSStream exte for(int i=0; i<data.length; i++) { data[i] = (byte)(i%256); } - NPOIFSStream stream = new NPOIFSStream(fs); + POIFSStream stream = new POIFSStream(fs); stream.updateContents(data); // Check we got another BAT - assertEquals(false, fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); - assertEquals(true, fs.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); + assertFalse(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + assertTrue(fs.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); // the BAT will be in the first spot of the new block assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(126)); @@ -575,8 +612,9 @@ public final class TestNPOIFSStream exte * Replaces data in an existing stream, with a bit * more data than before, in a 4096 byte block file */ + @Test public void testWriteStream4096() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); + POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); // 0 -> 1 -> 2 -> end assertEquals(1, fs.getNextBlock(0)); @@ -594,7 +632,7 @@ public final class TestNPOIFSStream exte for(int i=0; i<data.length; i++) { data[i] = (byte)(i%256); } - NPOIFSStream stream = new NPOIFSStream(fs, 0); + POIFSStream stream = new POIFSStream(fs, 0); stream.updateContents(data); @@ -629,303 +667,310 @@ public final class TestNPOIFSStream exte /** * Tests that we can write into the mini stream */ + @Test public void testWriteMiniStreams() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - NPOIFSMiniStore ministore = fs.getMiniStore(); - NPOIFSStream stream = new NPOIFSStream(ministore, 178); - - // 178 -> 179 -> 180 -> end - assertEquals(179, ministore.getNextBlock(178)); - assertEquals(180, ministore.getNextBlock(179)); - assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); - - - // Try writing 3 full blocks worth - byte[] data = new byte[64*3]; - for(int i=0; i<data.length; i++) { - data[i] = (byte)i; - } - stream = new NPOIFSStream(ministore, 178); - stream.updateContents(data); - - // Check - assertEquals(179, ministore.getNextBlock(178)); - assertEquals(180, ministore.getNextBlock(179)); - assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); - - stream = new NPOIFSStream(ministore, 178); - Iterator<ByteBuffer> it = stream.getBlockIterator(); - ByteBuffer b178 = it.next(); - ByteBuffer b179 = it.next(); - ByteBuffer b180 = it.next(); - assertEquals(false, it.hasNext()); - - assertEquals((byte)0x00, b178.get()); - assertEquals((byte)0x01, b178.get()); - assertEquals((byte)0x40, b179.get()); - assertEquals((byte)0x41, b179.get()); - assertEquals((byte)0x80, b180.get()); - assertEquals((byte)0x81, b180.get()); + try (InputStream is = _inst.openResourceAsStream("BlockSize512.zvi"); + POIFSFileSystem fs = new POIFSFileSystem(is)) { - - // Try writing just into 3 blocks worth - data = new byte[64*2 + 12]; - for(int i=0; i<data.length; i++) { - data[i] = (byte)(i+4); - } - stream = new NPOIFSStream(ministore, 178); - stream.updateContents(data); - - // Check - assertEquals(179, ministore.getNextBlock(178)); - assertEquals(180, ministore.getNextBlock(179)); - assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); - - stream = new NPOIFSStream(ministore, 178); - it = stream.getBlockIterator(); - b178 = it.next(); - b179 = it.next(); - b180 = it.next(); - assertEquals(false, it.hasNext()); - - assertEquals((byte)0x04, b178.get(0)); - assertEquals((byte)0x05, b178.get(1)); - assertEquals((byte)0x44, b179.get(0)); - assertEquals((byte)0x45, b179.get(1)); - assertEquals((byte)0x84, b180.get(0)); - assertEquals((byte)0x85, b180.get(1)); + POIFSMiniStore ministore = fs.getMiniStore(); - - // Try writing 1, should truncate - data = new byte[12]; - for(int i=0; i<data.length; i++) { - data[i] = (byte)(i+9); - } - stream = new NPOIFSStream(ministore, 178); - stream.updateContents(data); + // 178 -> 179 -> 180 -> end + assertEquals(179, ministore.getNextBlock(178)); + assertEquals(180, ministore.getNextBlock(179)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); + + + // Try writing 3 full blocks worth + byte[] data = new byte[64 * 3]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) i; + } + POIFSStream stream = new POIFSStream(ministore, 178); + stream.updateContents(data); + + // Check + assertEquals(179, ministore.getNextBlock(178)); + assertEquals(180, ministore.getNextBlock(179)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); + + stream = new POIFSStream(ministore, 178); + Iterator<ByteBuffer> it = stream.getBlockIterator(); + ByteBuffer b178 = it.next(); + ByteBuffer b179 = it.next(); + ByteBuffer b180 = it.next(); + assertFalse(it.hasNext()); + + assertEquals((byte) 0x00, b178.get()); + assertEquals((byte) 0x01, b178.get()); + assertEquals((byte) 0x40, b179.get()); + assertEquals((byte) 0x41, b179.get()); + assertEquals((byte) 0x80, b180.get()); + assertEquals((byte) 0x81, b180.get()); + + + // Try writing just into 3 blocks worth + data = new byte[64 * 2 + 12]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (i + 4); + } + stream = new POIFSStream(ministore, 178); + stream.updateContents(data); + + // Check + assertEquals(179, ministore.getNextBlock(178)); + assertEquals(180, ministore.getNextBlock(179)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); + + stream = new POIFSStream(ministore, 178); + it = stream.getBlockIterator(); + b178 = it.next(); + b179 = it.next(); + b180 = it.next(); + assertFalse(it.hasNext()); + + assertEquals((byte) 0x04, b178.get(0)); + assertEquals((byte) 0x05, b178.get(1)); + assertEquals((byte) 0x44, b179.get(0)); + assertEquals((byte) 0x45, b179.get(1)); + assertEquals((byte) 0x84, b180.get(0)); + assertEquals((byte) 0x85, b180.get(1)); + + + // Try writing 1, should truncate + data = new byte[12]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (i + 9); + } + stream = new POIFSStream(ministore, 178); + stream.updateContents(data); + + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(178)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(179)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(180)); + + stream = new POIFSStream(ministore, 178); + it = stream.getBlockIterator(); + b178 = it.next(); + assertFalse(it.hasNext()); + + assertEquals((byte) 0x09, b178.get(0)); + assertEquals((byte) 0x0a, b178.get(1)); + + + // Try writing 5, should extend + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(178)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(179)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(180)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(181)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(182)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(183)); + + data = new byte[64 * 4 + 12]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (i + 3); + } + stream = new POIFSStream(ministore, 178); + stream.updateContents(data); + + assertEquals(179, ministore.getNextBlock(178)); + assertEquals(180, ministore.getNextBlock(179)); + assertEquals(181, ministore.getNextBlock(180)); + assertEquals(182, ministore.getNextBlock(181)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(182)); + + stream = new POIFSStream(ministore, 178); + it = stream.getBlockIterator(); + b178 = it.next(); + b179 = it.next(); + b180 = it.next(); + ByteBuffer b181 = it.next(); + ByteBuffer b182 = it.next(); + assertFalse(it.hasNext()); + + assertEquals((byte) 0x03, b178.get(0)); + assertEquals((byte) 0x04, b178.get(1)); + assertEquals((byte) 0x43, b179.get(0)); + assertEquals((byte) 0x44, b179.get(1)); + assertEquals((byte) 0x83, b180.get(0)); + assertEquals((byte) 0x84, b180.get(1)); + assertEquals((byte) 0xc3, b181.get(0)); + assertEquals((byte) 0xc4, b181.get(1)); + assertEquals((byte) 0x03, b182.get(0)); + assertEquals((byte) 0x04, b182.get(1)); + + + // Write lots, so it needs another big block + ministore.getBlockAt(183); + try { + ministore.getBlockAt(184); + fail("Block 184 should be off the end of the list"); + } catch (IndexOutOfBoundsException e) { + } + + data = new byte[64 * 6 + 12]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (i + 1); + } + stream = new POIFSStream(ministore, 178); + stream.updateContents(data); + + // Should have added 2 more blocks to the chain + assertEquals(179, ministore.getNextBlock(178)); + assertEquals(180, ministore.getNextBlock(179)); + assertEquals(181, ministore.getNextBlock(180)); + assertEquals(182, ministore.getNextBlock(181)); + assertEquals(183, ministore.getNextBlock(182)); + assertEquals(184, ministore.getNextBlock(183)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(184)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(185)); + + // Block 184 should exist + ministore.getBlockAt(183); + ministore.getBlockAt(184); + ministore.getBlockAt(185); + + // Check contents + stream = new POIFSStream(ministore, 178); + it = stream.getBlockIterator(); + b178 = it.next(); + b179 = it.next(); + b180 = it.next(); + b181 = it.next(); + b182 = it.next(); + ByteBuffer b183 = it.next(); + ByteBuffer b184 = it.next(); + assertFalse(it.hasNext()); + + assertEquals((byte) 0x01, b178.get(0)); + assertEquals((byte) 0x02, b178.get(1)); + assertEquals((byte) 0x41, b179.get(0)); + assertEquals((byte) 0x42, b179.get(1)); + assertEquals((byte) 0x81, b180.get(0)); + assertEquals((byte) 0x82, b180.get(1)); + assertEquals((byte) 0xc1, b181.get(0)); + assertEquals((byte) 0xc2, b181.get(1)); + assertEquals((byte) 0x01, b182.get(0)); + assertEquals((byte) 0x02, b182.get(1)); + assertEquals((byte) 0x41, b183.get(0)); + assertEquals((byte) 0x42, b183.get(1)); + assertEquals((byte) 0x81, b184.get(0)); + assertEquals((byte) 0x82, b184.get(1)); - assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(178)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(179)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(180)); - - stream = new NPOIFSStream(ministore, 178); - it = stream.getBlockIterator(); - b178 = it.next(); - assertEquals(false, it.hasNext()); - - assertEquals((byte)0x09, b178.get(0)); - assertEquals((byte)0x0a, b178.get(1)); - - - // Try writing 5, should extend - assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(178)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(179)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(180)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(181)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(182)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(183)); - - data = new byte[64*4 + 12]; - for(int i=0; i<data.length; i++) { - data[i] = (byte)(i+3); - } - stream = new NPOIFSStream(ministore, 178); - stream.updateContents(data); - - assertEquals(179, ministore.getNextBlock(178)); - assertEquals(180, ministore.getNextBlock(179)); - assertEquals(181, ministore.getNextBlock(180)); - assertEquals(182, ministore.getNextBlock(181)); - assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(182)); - - stream = new NPOIFSStream(ministore, 178); - it = stream.getBlockIterator(); - b178 = it.next(); - b179 = it.next(); - b180 = it.next(); - ByteBuffer b181 = it.next(); - ByteBuffer b182 = it.next(); - assertEquals(false, it.hasNext()); - - assertEquals((byte)0x03, b178.get(0)); - assertEquals((byte)0x04, b178.get(1)); - assertEquals((byte)0x43, b179.get(0)); - assertEquals((byte)0x44, b179.get(1)); - assertEquals((byte)0x83, b180.get(0)); - assertEquals((byte)0x84, b180.get(1)); - assertEquals((byte)0xc3, b181.get(0)); - assertEquals((byte)0xc4, b181.get(1)); - assertEquals((byte)0x03, b182.get(0)); - assertEquals((byte)0x04, b182.get(1)); - - - // Write lots, so it needs another big block - ministore.getBlockAt(183); - try { - ministore.getBlockAt(184); - fail("Block 184 should be off the end of the list"); - } catch(IndexOutOfBoundsException e) {} - - data = new byte[64*6 + 12]; - for(int i=0; i<data.length; i++) { - data[i] = (byte)(i+1); } - stream = new NPOIFSStream(ministore, 178); - stream.updateContents(data); - - // Should have added 2 more blocks to the chain - assertEquals(179, ministore.getNextBlock(178)); - assertEquals(180, ministore.getNextBlock(179)); - assertEquals(181, ministore.getNextBlock(180)); - assertEquals(182, ministore.getNextBlock(181)); - assertEquals(183, ministore.getNextBlock(182)); - assertEquals(184, ministore.getNextBlock(183)); - assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(184)); - assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(185)); - - // Block 184 should exist - ministore.getBlockAt(183); - ministore.getBlockAt(184); - ministore.getBlockAt(185); - - // Check contents - stream = new NPOIFSStream(ministore, 178); - it = stream.getBlockIterator(); - b178 = it.next(); - b179 = it.next(); - b180 = it.next(); - b181 = it.next(); - b182 = it.next(); - ByteBuffer b183 = it.next(); - ByteBuffer b184 = it.next(); - assertEquals(false, it.hasNext()); - - assertEquals((byte)0x01, b178.get(0)); - assertEquals((byte)0x02, b178.get(1)); - assertEquals((byte)0x41, b179.get(0)); - assertEquals((byte)0x42, b179.get(1)); - assertEquals((byte)0x81, b180.get(0)); - assertEquals((byte)0x82, b180.get(1)); - assertEquals((byte)0xc1, b181.get(0)); - assertEquals((byte)0xc2, b181.get(1)); - assertEquals((byte)0x01, b182.get(0)); - assertEquals((byte)0x02, b182.get(1)); - assertEquals((byte)0x41, b183.get(0)); - assertEquals((byte)0x42, b183.get(1)); - assertEquals((byte)0x81, b184.get(0)); - assertEquals((byte)0x82, b184.get(1)); - - fs.close(); } /** * Craft a nasty file with a loop, and ensure we don't get stuck */ + @Test public void testWriteFailsOnLoop() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi")); - - // Hack the FAT so that it goes 0->1->2->0 - fs.setNextBlock(0, 1); - fs.setNextBlock(1, 2); - fs.setNextBlock(2, 0); - - // Try to write a large amount, should fail on the write - byte[] data = new byte[512*4]; - NPOIFSStream stream = new NPOIFSStream(fs, 0); - try { - stream.updateContents(data); - fail("Loop should have been detected but wasn't!"); - } catch(IllegalStateException e) {} - - // Now reset, and try on a small bit - // Should fail during the freeing set - fs.setNextBlock(0, 1); - fs.setNextBlock(1, 2); - fs.setNextBlock(2, 0); - - data = new byte[512]; - stream = new NPOIFSStream(fs, 0); - try { - stream.updateContents(data); - fail("Loop should have been detected but wasn't!"); - } catch(IllegalStateException e) {} - - fs.close(); + try (POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi"))) { + + // Hack the FAT so that it goes 0->1->2->0 + fs.setNextBlock(0, 1); + fs.setNextBlock(1, 2); + fs.setNextBlock(2, 0); + + // Try to write a large amount, should fail on the write + byte[] data = new byte[512 * 4]; + POIFSStream stream = new POIFSStream(fs, 0); + try { + stream.updateContents(data); + fail("Loop should have been detected but wasn't!"); + } catch (IllegalStateException e) { + } + + // Now reset, and try on a small bit + // Should fail during the freeing set + fs.setNextBlock(0, 1); + fs.setNextBlock(1, 2); + fs.setNextBlock(2, 0); + + data = new byte[512]; + stream = new POIFSStream(fs, 0); + try { + stream.updateContents(data); + fail("Loop should have been detected but wasn't!"); + } catch (IllegalStateException e) { + } + } } /** * Tests adding a new stream, writing and reading it. */ + @Test public void testReadWriteNewStream() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(); - NPOIFSStream stream = new NPOIFSStream(fs); - - // Check our filesystem has Properties then BAT - assertEquals(2, fs.getFreeBlock()); - BATBlock bat = fs.getBATBlockAndIndex(0).getBlock(); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK,bat.getValueAt(1)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(2)); - - // Check the stream as-is - assertEquals(POIFSConstants.END_OF_CHAIN, stream.getStartBlock()); - try { - stream.getBlockIterator(); - fail("Shouldn't be able to get an iterator before writing"); - } catch(IllegalStateException e) {} - - // Write in two blocks - byte[] data = new byte[512+20]; - for(int i=0; i<512; i++) { - data[i] = (byte)(i%256); - } - for(int i=512; i<data.length; i++) { - data[i] = (byte)(i%256 + 100); - } - stream.updateContents(data); - - // Check now - assertEquals(4, fs.getFreeBlock()); - bat = fs.getBATBlockAndIndex(0).getBlock(); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK,bat.getValueAt(1)); - assertEquals(3, bat.getValueAt(2)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(4)); - - - Iterator<ByteBuffer> it = stream.getBlockIterator(); - assertEquals(true, it.hasNext()); - ByteBuffer b = it.next(); - - byte[] read = new byte[512]; - b.get(read); - for(int i=0; i<read.length; i++) { - assertEquals("Wrong value at " + i, data[i], read[i]); - } - - assertEquals(true, it.hasNext()); - b = it.next(); - - read = new byte[512]; - b.get(read); - for(int i=0; i<20; i++) { - assertEquals(data[i+512], read[i]); - } - for(int i=20; i<read.length; i++) { - assertEquals(0, read[i]); + try (POIFSFileSystem fs = new POIFSFileSystem()) { + POIFSStream stream = new POIFSStream(fs); + + // Check our filesystem has Properties then BAT + assertEquals(2, fs.getFreeBlock()); + BATBlock bat = fs.getBATBlockAndIndex(0).getBlock(); + assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); + assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(2)); + + // Check the stream as-is + assertEquals(POIFSConstants.END_OF_CHAIN, stream.getStartBlock()); + try { + stream.getBlockIterator(); + fail("Shouldn't be able to get an iterator before writing"); + } catch (IllegalStateException e) { + } + + // Write in two blocks + byte[] data = new byte[512 + 20]; + for (int i = 0; i < 512; i++) { + data[i] = (byte) (i % 256); + } + for (int i = 512; i < data.length; i++) { + data[i] = (byte) (i % 256 + 100); + } + stream.updateContents(data); + + // Check now + assertEquals(4, fs.getFreeBlock()); + bat = fs.getBATBlockAndIndex(0).getBlock(); + assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); + assertEquals(3, bat.getValueAt(2)); + assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); + assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(4)); + + + Iterator<ByteBuffer> it = stream.getBlockIterator(); + assertTrue(it.hasNext()); + ByteBuffer b = it.next(); + + byte[] read = new byte[512]; + b.get(read); + for (int i = 0; i < read.length; i++) { + assertEquals("Wrong value at " + i, data[i], read[i]); + } + + assertTrue(it.hasNext()); + b = it.next(); + + read = new byte[512]; + b.get(read); + for (int i = 0; i < 20; i++) { + assertEquals(data[i + 512], read[i]); + } + for (int i = 20; i < read.length; i++) { + assertEquals(0, read[i]); + } + + assertFalse(it.hasNext()); } - - assertEquals(false, it.hasNext()); - - fs.close(); } /** * Writes a stream, then replaces it */ + @Test public void testWriteThenReplace() throws Exception { - NPOIFSFileSystem fs = new NPOIFSFileSystem(); + POIFSFileSystem fs = new POIFSFileSystem(); // Starts empty, other that Properties and BAT BATBlock bat = fs.getBATBlockAndIndex(0).getBlock(); @@ -937,9 +982,8 @@ public final class TestNPOIFSStream exte byte[] main4106 = new byte[4106]; main4106[0] = -10; main4106[4105] = -11; - DocumentEntry normal = fs.getRoot().createDocument( - "Normal", new ByteArrayInputStream(main4106)); - + fs.getRoot().createDocument("Normal", new ByteArrayInputStream(main4106)); + // Should have used 9 blocks assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); assertEquals(POIFSConstants.FAT_SECTOR_BLOCK,bat.getValueAt(1)); @@ -953,8 +997,8 @@ public final class TestNPOIFSStream exte assertEquals(10, bat.getValueAt(9)); assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(10)); assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11)); - - normal = (DocumentEntry)fs.getRoot().getEntry("Normal"); + + DocumentEntry normal = (DocumentEntry)fs.getRoot().getEntry("Normal"); assertEquals(4106, normal.getSize()); assertEquals(4106, ((DocumentNode)normal).getProperty().getSize()); @@ -964,7 +1008,7 @@ public final class TestNPOIFSStream exte main4096[0] = -10; main4096[4095] = -11; - NDocumentOutputStream nout = new NDocumentOutputStream(normal); + DocumentOutputStream nout = new DocumentOutputStream(normal); nout.write(main4096); nout.close(); @@ -1012,7 +1056,7 @@ public final class TestNPOIFSStream exte // Make longer, take 1 block at the end normal = (DocumentEntry)fs.getRoot().getEntry("Normal"); - nout = new NDocumentOutputStream(normal); + nout = new DocumentOutputStream(normal); nout.write(main4106); nout.close(); @@ -1038,7 +1082,7 @@ public final class TestNPOIFSStream exte // Make it small, will trigger the SBAT stream and free lots up byte[] mini = new byte[] { 42, 0, 1, 2, 3, 4, 42 }; normal = (DocumentEntry)fs.getRoot().getEntry("Normal"); - nout = new NDocumentOutputStream(normal); + nout = new DocumentOutputStream(normal); nout.write(mini); nout.close(); @@ -1062,7 +1106,7 @@ public final class TestNPOIFSStream exte // Finally back to big again - nout = new NDocumentOutputStream(normal); + nout = new DocumentOutputStream(normal); nout.write(main4096); nout.close(); @@ -1112,4 +1156,1716 @@ public final class TestNPOIFSStream exte fs.close(); } + + + /** + * Returns test files with 512 byte and 4k block sizes, loaded + * both from InputStreams and Files + */ + private POIFSFileSystem[] get512and4kFileAndInput() throws IOException { + POIFSFileSystem fsA = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + POIFSFileSystem fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + POIFSFileSystem fsC = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); + POIFSFileSystem fsD = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); + return new POIFSFileSystem[] {fsA,fsB,fsC,fsD}; + } + + private static void assertBATCount(POIFSFileSystem fs, int expectedBAT, int expectedXBAT) throws IOException { + int foundBAT = 0; + int foundXBAT = 0; + int sz = (int)(fs.size() / fs.getBigBlockSize()); + for (int i=0; i<sz; i++) { + if(fs.getNextBlock(i) == POIFSConstants.FAT_SECTOR_BLOCK) { + foundBAT++; + } + if(fs.getNextBlock(i) == POIFSConstants.DIFAT_SECTOR_BLOCK) { + foundXBAT++; + } + } + assertEquals("Wrong number of BATs", expectedBAT, foundBAT); + assertEquals("Wrong number of XBATs with " + expectedBAT + " BATs", expectedXBAT, foundXBAT); + } + private void assertContentsMatches(byte[] expected, DocumentEntry doc) throws IOException { + DocumentInputStream inp = new DocumentInputStream(doc); + byte[] contents = new byte[doc.getSize()]; + assertEquals(doc.getSize(), inp.read(contents)); + inp.close(); + + if (expected != null) { + assertThat(expected, equalTo(contents)); + } + } + + private static HeaderBlock writeOutAndReadHeader(POIFSFileSystem fs) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + fs.writeFilesystem(baos); + + return new HeaderBlock(new ByteArrayInputStream(baos.toByteArray())); + } + + private static POIFSFileSystem writeOutAndReadBack(POIFSFileSystem original) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + original.writeFilesystem(baos); + return new POIFSFileSystem(new ByteArrayInputStream(baos.toByteArray())); + } + + private static POIFSFileSystem writeOutFileAndReadBack(POIFSFileSystem original) throws IOException { + final File file = TempFile.createTempFile("TestPOIFS", ".ole2"); + try (OutputStream fout = new FileOutputStream(file)) { + original.writeFilesystem(fout); + } + return new POIFSFileSystem(file, false); + } + + @Test + public void basicOpen() throws IOException { + POIFSFileSystem fsA, fsB; + + // With a simple 512 block file + fsA = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + assertEquals(512, fs.getBigBlockSize()); + } + fsA.close(); + fsB.close(); + + // Now with a simple 4096 block file + fsA = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); + fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + assertEquals(4096, fs.getBigBlockSize()); + } + fsA.close(); + fsB.close(); + } + + @Test + public void propertiesAndFatOnRead() throws IOException { + POIFSFileSystem fsA, fsB; + + // With a simple 512 block file + fsA = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + // Check the FAT was properly processed: + // Verify we only got one block + fs.getBATBlockAndIndex(0); + fs.getBATBlockAndIndex(1); + try { + fs.getBATBlockAndIndex(140); + fail("Should only be one BAT, but a 2nd was found"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + + // Verify a few next offsets + // 97 -> 98 -> END + assertEquals(98, fs.getNextBlock(97)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); + + + // Check the properties + PropertyTable props = fs._get_property_table(); + assertEquals(90, props.getStartBlock()); + assertEquals(7, props.countBlocks()); + + // Root property tells us about the Mini Stream + RootProperty root = props.getRoot(); + assertEquals("Root Entry", root.getName()); + assertEquals(11564, root.getSize()); + assertEquals(0, root.getStartBlock()); + + // Check its children too + Property prop; + Iterator<Property> pi = root.getChildren(); + prop = pi.next(); + assertEquals("Thumbnail", prop.getName()); + prop = pi.next(); + assertEquals("\u0005DocumentSummaryInformation", prop.getName()); + prop = pi.next(); + assertEquals("\u0005SummaryInformation", prop.getName()); + prop = pi.next(); + assertEquals("Image", prop.getName()); + prop = pi.next(); + assertEquals("Tags", prop.getName()); + assertFalse(pi.hasNext()); + + + // Check the SBAT (Small Blocks FAT) was properly processed + POIFSMiniStore ministore = fs.getMiniStore(); + + // Verify we only got two SBAT blocks + ministore.getBATBlockAndIndex(0); + ministore.getBATBlockAndIndex(128); + try { + ministore.getBATBlockAndIndex(256); + fail("Should only be two SBATs, but a 3rd was found"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + + // Verify a few offsets: 0->50 is a stream + for(int i=0; i<50; i++) { + assertEquals(i+1, ministore.getNextBlock(i)); + } + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50)); + + fs.close(); + } + + // Now with a simple 4096 block file + fsA = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); + fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + // Check the FAT was properly processed + // Verify we only got one block + fs.getBATBlockAndIndex(0); + fs.getBATBlockAndIndex(1); + try { + fs.getBATBlockAndIndex(1040); + fail("Should only be one BAT, but a 2nd was found"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + + // Verify a few next offsets + // 0 -> 1 -> 2 -> END + assertEquals(1, fs.getNextBlock(0)); + assertEquals(2, fs.getNextBlock(1)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); + + + // Check the properties + PropertyTable props = fs._get_property_table(); + assertEquals(12, props.getStartBlock()); + assertEquals(1, props.countBlocks()); + + // Root property tells us about the Mini Stream + RootProperty root = props.getRoot(); + assertEquals("Root Entry", root.getName()); + assertEquals(11564, root.getSize()); + assertEquals(0, root.getStartBlock()); + + // Check its children too + Property prop; + Iterator<Property> pi = root.getChildren(); + prop = pi.next(); + assertEquals("Thumbnail", prop.getName()); + prop = pi.next(); + assertEquals("\u0005DocumentSummaryInformation", prop.getName()); + prop = pi.next(); + assertEquals("\u0005SummaryInformation", prop.getName()); + prop = pi.next(); + assertEquals("Image", prop.getName()); + prop = pi.next(); + assertEquals("Tags", prop.getName()); + assertFalse(pi.hasNext()); + + + // Check the SBAT (Small Blocks FAT) was properly processed + POIFSMiniStore ministore = fs.getMiniStore(); + + // Verify we only got one SBAT block + ministore.getBATBlockAndIndex(0); + ministore.getBATBlockAndIndex(128); + ministore.getBATBlockAndIndex(1023); + try { + ministore.getBATBlockAndIndex(1024); + fail("Should only be one SBAT, but a 2nd was found"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + + // Verify a few offsets: 0->50 is a stream + for(int i=0; i<50; i++) { + assertEquals(i+1, ministore.getNextBlock(i)); + } + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(50)); + + fs.close(); + } + } + + /** + * Check that for a given block, we can correctly figure + * out what the next one is + */ + @Test + public void nextBlock() throws IOException { + POIFSFileSystem fsA = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + POIFSFileSystem fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + // 0 -> 21 are simple + for(int i=0; i<21; i++) { + assertEquals(i+1, fs.getNextBlock(i)); + } + // 21 jumps to 89, then ends + assertEquals(89, fs.getNextBlock(21)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(89)); + + // 22 -> 88 simple sequential stream + for(int i=22; i<88; i++) { + assertEquals(i+1, fs.getNextBlock(i)); + } + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(88)); + + // 90 -> 96 is another stream + for(int i=90; i<96; i++) { + assertEquals(i+1, fs.getNextBlock(i)); + } + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(96)); + + // 97+98 is another + assertEquals(98, fs.getNextBlock(97)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98)); + + // 99 is our FAT block + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); + + // 100 onwards is free + for(int i=100; i<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) { + assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(i)); + } + + fs.close(); + } + + // Quick check on 4096 byte blocks too + fsA = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); + fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + // 0 -> 1 -> 2 -> end + assertEquals(1, fs.getNextBlock(0)); + assertEquals(2, fs.getNextBlock(1)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); + + // 4 -> 11 then end + for(int i=4; i<11; i++) { + assertEquals(i+1, fs.getNextBlock(i)); + } + assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(11)); + + fs.close(); + } + } + + /** + * Check we get the right data back for each block + */ + @Test + public void getBlock() throws IOException { + POIFSFileSystem fsA = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + POIFSFileSystem fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + ByteBuffer b; + + // The 0th block is the first data block + b = fs.getBlockAt(0); + assertEquals((byte)0x9e, b.get()); + assertEquals((byte)0x75, b.get()); + assertEquals((byte)0x97, b.get()); + assertEquals((byte)0xf6, b.get()); + + // And the next block + b = fs.getBlockAt(1); + assertEquals((byte)0x86, b.get()); + assertEquals((byte)0x09, b.get()); + assertEquals((byte)0x22, b.get()); + assertEquals((byte)0xfb, b.get()); + + // Check the final block too + b = fs.getBlockAt(99); + assertEquals((byte)0x01, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x02, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + + fs.close(); + } + + // Quick check on 4096 byte blocks too + fsA = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); + fsB = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); + for(POIFSFileSystem fs : new POIFSFileSystem[] {fsA,fsB}) { + ByteBuffer b; + + // The 0th block is the first data block + b = fs.getBlockAt(0); + assertEquals((byte)0x9e, b.get()); + assertEquals((byte)0x75, b.get()); + assertEquals((byte)0x97, b.get()); + assertEquals((byte)0xf6, b.get()); + + // And the next block + b = fs.getBlockAt(1); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x03, b.get()); + assertEquals((byte)0x00, b.get()); + + // The 14th block is the FAT + b = fs.getBlockAt(14); + assertEquals((byte)0x01, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x02, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + assertEquals((byte)0x00, b.get()); + + fs.close(); + } + } + + /** + * Ask for free blocks where there are some already + * to be had from the FAT + */ + @Test + public void getFreeBlockWithSpare() throws IOException { + POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); + + // Our first BAT block has spares + assertTrue(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + + // First free one is 100 + assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103)); + + // Ask, will get 100 + assertEquals(100, fs.getFreeBlock()); + + // Ask again, will still get 100 as not written to + assertEquals(100, fs.getFreeBlock()); + + // Allocate it, then ask again + fs.setNextBlock(100, POIFSConstants.END_OF_CHAIN); + assertEquals(101, fs.getFreeBlock()); + + // All done + fs.close(); + } + + /** + * Ask for free blocks where no free ones exist, and so the + * file needs to be extended and another BAT/XBAT added + */ + @Test + public void getFreeBlockWithNoneSpare() throws IOException { + POIFSFileSystem fs1 = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + int free; + + // We have one BAT at block 99 + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(99)); + assertBATCount(fs1, 1, 0); + + // We've spare ones from 100 to 128 + for(int i=100; i<128; i++) { + assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(i)); + } + + // Check our BAT knows it's free + assertTrue(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + + // Allocate all the spare ones + for(int i=100; i<128; i++) { + fs1.setNextBlock(i, POIFSConstants.END_OF_CHAIN); + } + + // BAT is now full, but there's only the one + assertFalse(fs1.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); + try { + assertFalse(fs1.getBATBlockAndIndex(128).getBlock().hasFreeSectors()); + fail("Should only be one BAT"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + assertBATCount(fs1, 1, 0); + + + // Now ask for a free one, will need to extend the file + assertEquals(129, fs1.getFreeBlock()); + + 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)); + + // We now have 2 BATs, but no XBATs + assertBATCount(fs1, 2, 0); + + + // Fill up to hold 109 BAT blocks + for(int i=0; i<109; i++) { + fs1.getFreeBlock(); + int startOffset = i*128; + while( fs1.getBATBlockAndIndex(startOffset).getBlock().hasFreeSectors() ) { + free = fs1.getFreeBlock(); + fs1.setNextBlock(free, POIFSConstants.END_OF_CHAIN); + } + } + + assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors()); + try { + assertFalse(fs1.getBATBlockAndIndex(109 * 128).getBlock().hasFreeSectors()); + fail("Should only be 109 BATs"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + + // We now have 109 BATs, but no XBATs + assertBATCount(fs1, 109, 0); + + + // Ask for it to be written out, and check the header + HeaderBlock header = writeOutAndReadHeader(fs1); + assertEquals(109, header.getBATCount()); + assertEquals(0, header.getXBATCount()); + + + // Ask for another, will get our first XBAT + free = fs1.getFreeBlock(); + assertTrue("Had: " + free, free > 0); + + assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors()); + assertTrue(fs1.getBATBlockAndIndex(110 * 128 - 1).getBlock().hasFreeSectors()); + try { + assertFalse(fs1.getBATBlockAndIndex(110 * 128).getBlock().hasFreeSectors()); + fail("Should only be 110 BATs"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + assertBATCount(fs1, 110, 1); + + header = writeOutAndReadHeader(fs1); + assertEquals(110, header.getBATCount()); + assertEquals(1, header.getXBATCount()); + + + // Fill the XBAT, which means filling 127 BATs + for(int i=109; i<109+127; i++) { + fs1.getFreeBlock(); + int startOffset = i*128; + while( fs1.getBATBlockAndIndex(startOffset).getBlock().hasFreeSectors() ) { + free = fs1.getFreeBlock(); + fs1.setNextBlock(free, POIFSConstants.END_OF_CHAIN); + } + assertBATCount(fs1, i+1, 1); + } + + // Should now have 109+127 = 236 BATs + assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors()); + try { + assertFalse(fs1.getBATBlockAndIndex(236 * 128).getBlock().hasFreeSectors()); + fail("Should only be 236 BATs"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + assertBATCount(fs1, 236, 1); + + + // Ask for another, will get our 2nd XBAT + free = fs1.getFreeBlock(); + assertTrue("Had: " + free, free > 0); + + assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors()); + assertTrue(fs1.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors()); + try { + assertFalse(fs1.getBATBlockAndIndex(237 * 128).getBlock().hasFreeSectors()); + fail("Should only be 237 BATs"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + + + // Check the counts now + assertBATCount(fs1, 237, 2); + + // Check the header + header = writeOutAndReadHeader(fs1); + assertNotNull(header); + + // Now, write it out, and read it back in again fully + POIFSFileSystem fs2 = writeOutAndReadBack(fs1); + fs1.close(); + + // Check that it is seen correctly + assertBATCount(fs2, 237, 2); + + assertFalse(fs2.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors()); + assertTrue(fs2.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors()); + try { + assertFalse(fs2.getBATBlockAndIndex(237 * 128).getBlock().hasFreeSectors()); + fail("Should only be 237 BATs"); + } catch(IndexOutOfBoundsException e) { + // expected here + } + + + // All done + fs2.close(); + } + + /** + * Test that we can correctly get the list of directory + * entries, and the details on the files in them + */ + @Test + public void listEntries() throws IOException { + for(POIFSFileSystem fs : get512and4kFileAndInput()) { + DirectoryEntry root = fs.getRoot(); + assertEquals(5, root.getEntryCount()); + + // Check by the names + Entry thumbnail = root.getEntry("Thumbnail"); + Entry dsi = root.getEntry("\u0005DocumentSummaryInformation"); + Entry si = root.getEntry("\u0005SummaryInformation"); + Entry image = root.getEntry("Image"); + Entry tags = root.getEntry("Tags"); + + assertFalse(thumbnail.isDirectoryEntry()); + assertFalse(dsi.isDirectoryEntry()); + assertFalse(si.isDirectoryEntry()); + assertTrue(image.isDirectoryEntry()); + assertFalse(tags.isDirectoryEntry()); + + // Check via the iterator + Iterator<Entry> it = root.getEntries(); + assertEquals(thumbnail.getName(), it.next().getName()); + assertEquals(dsi.getName(), it.next().getName()); + assertEquals(si.getName(), it.next().getName()); + assertEquals(image.getName(), it.next().getName()); + assertEquals(tags.getName(), it.next().getName()); + + // Look inside another + DirectoryEntry imageD = (DirectoryEntry)image; + assertEquals(7, imageD.getEntryCount()); + + fs.close(); + } + } + + /** + * Tests that we can get the correct contents for + * a document in the filesystem + */ + @Test + public void getDocumentEntry() throws Exception { + for(POIFSFileSystem fs : get512and4kFileAndInput()) { + DirectoryEntry root = fs.getRoot(); + Entry si = root.getEntry("\u0005SummaryInformation"); + + assertTrue(si.isDocumentEntry()); + DocumentNode doc = (DocumentNode)si; + + // Check we can read it + assertContentsMatches(null, doc); + + // Now try to build the property set + DocumentInputStream inp = new DocumentInputStream(doc); + PropertySet ps = PropertySetFactory.create(inp); + SummaryInformation inf = (SummaryInformation)ps; + + // Check some bits in it + assertNull(inf.getApplicationName()); + assertNull(inf.getAuthor()); + assertNull(inf.getSubject()); + assertEquals(131333, inf.getOSVersion()); + + // Finish with this one + inp.close(); + + + // Try the other summary information + si = root.getEntry("\u0005DocumentSummaryInformation"); + assertTrue(si.isDocumentEntry()); + doc = (DocumentNode)si; + assertContentsMatches(null, doc); + + inp = new DocumentInputStream(doc); + ps = PropertySetFactory.create(inp); + DocumentSummaryInformation dinf = (DocumentSummaryInformation)ps; + assertEquals(131333, dinf.getOSVersion()); + + fs.close(); + } + } + + /** + * Read a file, write it and read it again. + * Then, alter+add some streams, write and read + */ + @Test + public void readWriteRead() throws Exception { + SummaryInformation sinf; + DocumentSummaryInformation dinf; + DirectoryEntry root, testDir; + + for(POIFSFileSystem fs1 : get512and4kFileAndInput()) { + // Check we can find the entries we expect + root = fs1.getRoot(); + assertEquals(5, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Tags")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + + // Write out, re-load + POIFSFileSystem fs2 = writeOutAndReadBack(fs1); + fs1.close(); + + // Check they're still there + root = fs2.getRoot(); + assertEquals(5, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Tags")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + + // Check the contents of them - parse the summary block and check + sinf = (SummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, sinf.getOSVersion()); + + dinf = (DocumentSummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, dinf.getOSVersion()); + + + // Add a test mini stream + testDir = root.createDirectory("Testing 123"); + testDir.createDirectory("Testing 456"); + testDir.createDirectory("Testing 789"); + byte[] mini = new byte[] { 42, 0, 1, 2, 3, 4, 42 }; + testDir.createDocument("Mini", new ByteArrayInputStream(mini)); + + + // Write out, re-load + POIFSFileSystem fs3 = writeOutAndReadBack(fs2); + fs2.close(); + + root = fs3.getRoot(); + testDir = (DirectoryEntry)root.getEntry("Testing 123"); + assertEquals(6, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Tags")); + assertThat(root.getEntryNames(), hasItem("Testing 123")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + + // Check old and new are there + sinf = (SummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, sinf.getOSVersion()); + + dinf = (DocumentSummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, dinf.getOSVersion()); + + assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini")); + + + // Write out and read once more, just to be sure + POIFSFileSystem fs4 = writeOutAndReadBack(fs3); + fs3.close(); + + root = fs4.getRoot(); + testDir = (DirectoryEntry)root.getEntry("Testing 123"); + assertEquals(6, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Tags")); + assertThat(root.getEntryNames(), hasItem("Testing 123")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + sinf = (SummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, sinf.getOSVersion()); + + dinf = (DocumentSummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, dinf.getOSVersion()); + + assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini")); + + + // Add a full stream, delete a full stream + byte[] main4096 = new byte[4096]; + main4096[0] = -10; + main4096[4095] = -11; + testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096)); + + root.getEntry("Tags").delete(); + + + // Write out, re-load + POIFSFileSystem fs5 = writeOutAndReadBack(fs4); + fs4.close(); + + // Check it's all there + root = fs5.getRoot(); + testDir = (DirectoryEntry)root.getEntry("Testing 123"); + assertEquals(5, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Testing 123")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + + // Check old and new are there + sinf = (SummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, sinf.getOSVersion()); + + dinf = (DocumentSummaryInformation)PropertySetFactory.create(new DocumentInputStream( + (DocumentEntry)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME))); + assertEquals(131333, dinf.getOSVersion()); + + assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini")); + assertContentsMatches(main4096, (DocumentEntry)testDir.getEntry("Normal4096")); + + + // Delete a directory, and add one more + testDir.getEntry("Testing 456").delete(); + testDir.createDirectory("Testing ABC"); + + + // Save + POIFSFileSystem fs6 = writeOutAndReadBack(fs5); + fs5.close(); + + // Check + root = fs6.getRoot(); + testDir = (DirectoryEntry)root.getEntry("Testing 123"); + + assertEquals(5, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Testing 123")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + assertEquals(4, testDir.getEntryCount()); + assertThat(testDir.getEntryNames(), hasItem("Mini")); + assertThat(testDir.getEntryNames(), hasItem("Normal4096")); + assertThat(testDir.getEntryNames(), hasItem("Testing 789")); + assertThat(testDir.getEntryNames(), hasItem("Testing ABC")); + + + // Add another mini stream + byte[] mini2 = new byte[] { -42, 0, -1, -2, -3, -4, -42 }; + testDir.createDocument("Mini2", new ByteArrayInputStream(mini2)); + + // Save, load, check + POIFSFileSystem fs7 = writeOutAndReadBack(fs6); + fs6.close(); + + root = fs7.getRoot(); + testDir = (DirectoryEntry)root.getEntry("Testing 123"); + + assertEquals(5, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Testing 123")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + assertEquals(5, testDir.getEntryCount()); + assertThat(testDir.getEntryNames(), hasItem("Mini")); + assertThat(testDir.getEntryNames(), hasItem("Mini2")); + assertThat(testDir.getEntryNames(), hasItem("Normal4096")); + assertThat(testDir.getEntryNames(), hasItem("Testing 789")); + assertThat(testDir.getEntryNames(), hasItem("Testing ABC")); + + assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini")); + assertContentsMatches(mini2, (DocumentEntry)testDir.getEntry("Mini2")); + assertContentsMatches(main4096, (DocumentEntry)testDir.getEntry("Normal4096")); + + + // Delete a mini stream, add one more + testDir.getEntry("Mini").delete(); + + byte[] mini3 = new byte[] { 42, 0, 42, 0, 42, 0, 42 }; + testDir.createDocument("Mini3", new ByteArrayInputStream(mini3)); + + + // Save, load, check + POIFSFileSystem fs8 = writeOutAndReadBack(fs7); + fs7.close(); + + root = fs8.getRoot(); + testDir = (DirectoryEntry)root.getEntry("Testing 123"); + + assertEquals(5, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Testing 123")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + assertEquals(5, testDir.getEntryCount()); + assertThat(testDir.getEntryNames(), hasItem("Mini2")); + assertThat(testDir.getEntryNames(), hasItem("Mini3")); + assertThat(testDir.getEntryNames(), hasItem("Normal4096")); + assertThat(testDir.getEntryNames(), hasItem("Testing 789")); + assertThat(testDir.getEntryNames(), hasItem("Testing ABC")); + + assertContentsMatches(mini2, (DocumentEntry)testDir.getEntry("Mini2")); + assertContentsMatches(mini3, (DocumentEntry)testDir.getEntry("Mini3")); + assertContentsMatches(main4096, (DocumentEntry)testDir.getEntry("Normal4096")); + + + // Change some existing streams + POIFSDocument mini2Doc = new POIFSDocument((DocumentNode)testDir.getEntry("Mini2")); + mini2Doc.replaceContents(new ByteArrayInputStream(mini)); + + byte[] main4106 = new byte[4106]; + main4106[0] = 41; + main4106[4105] = 42; + POIFSDocument mainDoc = new POIFSDocument((DocumentNode)testDir.getEntry("Normal4096")); + mainDoc.replaceContents(new ByteArrayInputStream(main4106)); + + + // Re-check + POIFSFileSystem fs9 = writeOutAndReadBack(fs8); + fs8.close(); + + root = fs9.getRoot(); + testDir = (DirectoryEntry)root.getEntry("Testing 123"); + + assertEquals(5, root.getEntryCount()); + assertThat(root.getEntryNames(), hasItem("Thumbnail")); + assertThat(root.getEntryNames(), hasItem("Image")); + assertThat(root.getEntryNames(), hasItem("Testing 123")); + assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation")); + assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation")); + + assertEquals(5, testDir.getEntryCount()); + assertThat(testDir.getEntryNames(), hasItem("Mini2")); + assertThat(testDir.getEntryNames(), hasItem("Mini3")); + assertThat(testDir.getEntryNames(), hasItem("Normal4096")); + assertThat(testDir.getEntryNames(), hasItem("Testing 789")); + assertThat(testDir.getEntryNames(), hasItem("Testing ABC")); + + assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini2")); + assertContentsMatches(mini3, (DocumentEntry)testDir.getEntry("Mini3")); + assertContentsMatches(main4106, (DocumentEntry)testDir.getEntry("Normal4096")); + + + // All done + fs9.close(); + } + } + + /** + * Create a new file, write it and read it again + * Then, add some streams, write and read + */ + @Test + public void createWriteRead() throws IOException { + POIFSFileSystem fs1 = new POIFSFileSystem(); + DocumentEntry miniDoc; + DocumentEntry normDoc; + + // Initially has Properties + BAT but not SBAT + assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(1)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(2)); + + // Check that the SBAT is empty + assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getRoot().getProperty().getStartBlock()); + + // Check that properties table was given block 0 + assertEquals(0, fs1._get_property_table().getStartBlock()); + + // Write and read it + POIFSFileSystem fs2 = writeOutAndReadBack(fs1); + fs1.close(); + + // No change, SBAT remains empty + assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs2.getNextBlock(1)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs2.getNextBlock(2)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs2.getNextBlock(3)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getRoot().getProperty().getStartBlock()); + assertEquals(0, fs2._get_property_table().getStartBlock()); + fs2.close(); + + // Check the same but with saving to a file + POIFSFileSystem fs3 = new POIFSFileSystem(); + POIFSFileSystem fs4 = writeOutFileAndReadBack(fs3); + fs3.close(); + + // Same, no change, SBAT remains empty + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(2)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(3)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getRoot().getProperty().getStartBlock()); + assertEquals(0, fs4._get_property_table().getStartBlock()); + + + + // Put everything within a new directory + DirectoryEntry testDir = fs4.createDirectory("Test Directory"); + + // Add a new Normal Stream (Normal Streams minimum 4096 bytes) + byte[] main4096 = new byte[4096]; + main4096[0] = -10; + main4096[4095] = -11; + testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096)); + + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1)); + assertEquals(3, fs4.getNextBlock(2)); + assertEquals(4, fs4.getNextBlock(3)); + assertEquals(5, fs4.getNextBlock(4)); + assertEquals(6, fs4.getNextBlock(5)); + assertEquals(7, fs4.getNextBlock(6)); + assertEquals(8, fs4.getNextBlock(7)); + assertEquals(9, fs4.getNextBlock(8)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(9)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(10)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(11)); + // SBAT still unused + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getRoot().getProperty().getStartBlock()); + + + // Add a bigger Normal Stream + byte[] main5124 = new byte[5124]; + main5124[0] = -22; + main5124[5123] = -33; + testDir.createDocument("Normal5124", new ByteArrayInputStream(main5124)); + + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1)); + assertEquals(3, fs4.getNextBlock(2)); + assertEquals(4, fs4.getNextBlock(3)); + assertEquals(5, fs4.getNextBlock(4)); + assertEquals(6, fs4.getNextBlock(5)); + assertEquals(7, fs4.getNextBlock(6)); + assertEquals(8, fs4.getNextBlock(7)); + assertEquals(9, fs4.getNextBlock(8)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(9)); + + assertEquals(11, fs4.getNextBlock(10)); + assertEquals(12, fs4.getNextBlock(11)); + assertEquals(13, fs4.getNextBlock(12)); + assertEquals(14, fs4.getNextBlock(13)); + assertEquals(15, fs4.getNextBlock(14)); + assertEquals(16, fs4.getNextBlock(15)); + assertEquals(17, fs4.getNextBlock(16)); + assertEquals(18, fs4.getNextBlock(17)); + assertEquals(19, fs4.getNextBlock(18)); + assertEquals(20, fs4.getNextBlock(19)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(20)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(21)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(22)); + + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getRoot().getProperty().getStartBlock()); + + + // Now Add a mini stream + byte[] mini = new byte[] { 42, 0, 1, 2, 3, 4, 42 }; + testDir.createDocument("Mini", new ByteArrayInputStream(mini)); + + // Mini stream will get one block for fat + one block for data + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(0)); + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs4.getNextBlock(1)); + assertEquals(3, fs4.getNextBlock(2)); + assertEquals(4, fs4.getNextBlock(3)); + assertEquals(5, fs4.getNextBlock(4)); + assertEquals(6, fs4.getNextBlock(5)); + assertEquals(7, fs4.getNextBlock(6)); + assertEquals(8, fs4.getNextBlock(7)); + assertEquals(9, fs4.getNextBlock(8)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(9)); + + assertEquals(11, fs4.getNextBlock(10)); + assertEquals(12, fs4.getNextBlock(11)); + assertEquals(13, fs4.getNextBlock(12)); + assertEquals(14, fs4.getNextBlock(13)); + assertEquals(15, fs4.getNextBlock(14)); + assertEquals(16, fs4.getNextBlock(15)); + assertEquals(17, fs4.getNextBlock(16)); + assertEquals(18, fs4.getNextBlock(17)); + assertEquals(19, fs4.getNextBlock(18)); + assertEquals(20, fs4.getNextBlock(19)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(20)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(21)); + assertEquals(POIFSConstants.END_OF_CHAIN, fs4.getNextBlock(22)); + assertEquals(POIFSConstants.UNUSED_BLOCK, fs4.getNextBlock(23)); + + // Check the mini stream location was set + // (21 is mini fat, 22 is first mini stream block) + assertEquals(22, fs4.getRoot().getProperty().getStartBlock()); + + + // Write and read back + POIFSFileSystem fs5 = writeOutAndReadBack(fs4); + fs4.close(); + HeaderBlock header = writeOutAndReadHeader(fs5); + + // Check the header has the right points in it + assertEquals(1, header.getBATCount()); + assertEquals(1, header.getBATArray()[0]); + assertEquals(0, header.getPropertyStart()); + assertEquals(1, header.getSBATCount()); + assertEquals(21, header.getSBATStart()); + assertEquals(22, fs5._get_property_table().getRoot().getStartBlock()); + + // Block use should be almost the same, except the properties + // stream will have grown out to cover 2 blocks + // Check the block use is all unchanged + assertEquals(23, fs5.getNextBlock(0)); // Properties now extends over 2 blocks + assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs5.getNextBlock(1)); + + assertEquals(3, fs5.getNextBlock(2)); + assertEquals(4, fs5.getNextBlock(3)); + assertEquals(5, fs5.getNextBlock(4)); + assertEquals(6, fs5.getNextBlock(5)); + assertEquals(7, fs5.getNextBlock(6)); + assertEquals(8, fs5.getNextBlock(7)); + assertEquals(9, fs5.getNextBlock(8));
[... 627 lines stripped ...] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
