diff options
author | Andreas Beeker <kiwiwings@apache.org> | 2021-03-27 14:03:16 +0000 |
---|---|---|
committer | Andreas Beeker <kiwiwings@apache.org> | 2021-03-27 14:03:16 +0000 |
commit | 37791e4bdfc706aa5684745594260f243b4be7ee (patch) | |
tree | a8dd8d0976fc478074d52cd3de79e0e6b5e6a33a /src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java | |
parent | 2bb3839bfe3e3bacff79f8157465633e311239ce (diff) | |
download | poi-37791e4bdfc706aa5684745594260f243b4be7ee.tar.gz poi-37791e4bdfc706aa5684745594260f243b4be7ee.zip |
65206 - Migrate ant / maven to gradle build
update gradle files and project structure along https://github.com/centic9/poi/tree/gradle_build
remove eclipse IDE project files
remove obsolete record generator files
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1888111 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java')
-rw-r--r-- | src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java | 2792 |
1 files changed, 0 insertions, 2792 deletions
diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java b/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java deleted file mode 100644 index 2a2a8122d1..0000000000 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSStream.java +++ /dev/null @@ -1,2792 +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 static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - -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 java.util.NoSuchElementException; - -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.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -/** - * Tests {@link POIFSStream} - */ -final class TestPOIFSStream { - private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance(); - - /** - * Read a single block stream - */ - @Test - void testReadTinyStream() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); - - // 98 is actually the last block in a two block stream... - POIFSStream stream = new POIFSStream(fs, 98); - Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertTrue(i.hasNext()); - ByteBuffer b = i.next(); - assertFalse(i.hasNext()); - - // Check the contents - assertEquals((byte) 0x81, b.get()); - assertEquals((byte) 0x00, b.get()); - assertEquals((byte) 0x00, b.get()); - assertEquals((byte) 0x00, b.get()); - assertEquals((byte) 0x82, b.get()); - assertEquals((byte) 0x00, b.get()); - assertEquals((byte) 0x00, b.get()); - assertEquals((byte) 0x00, b.get()); - - fs.close(); - } - - /** - * Read a stream with only two blocks in it - */ - @Test - void testReadShortStream() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize512.zvi")); - - // 97 -> 98 -> end - POIFSStream stream = new POIFSStream(fs, 97); - Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertTrue(i.hasNext()); - ByteBuffer b97 = i.next(); - assertTrue(i.hasNext()); - ByteBuffer b98 = i.next(); - assertFalse(i.hasNext()); - - // Check the contents of the 1st block - assertEquals((byte) 0x01, b97.get()); - assertEquals((byte) 0x00, b97.get()); - assertEquals((byte) 0x00, b97.get()); - assertEquals((byte) 0x00, b97.get()); - assertEquals((byte) 0x02, b97.get()); - assertEquals((byte) 0x00, b97.get()); - assertEquals((byte) 0x00, b97.get()); - assertEquals((byte) 0x00, b97.get()); - - // Check the contents of the 2nd block - assertEquals((byte) 0x81, b98.get()); - assertEquals((byte) 0x00, b98.get()); - assertEquals((byte) 0x00, b98.get()); - assertEquals((byte) 0x00, b98.get()); - assertEquals((byte) 0x82, b98.get()); - assertEquals((byte) 0x00, b98.get()); - assertEquals((byte) 0x00, b98.get()); - assertEquals((byte) 0x00, b98.get()); - - fs.close(); - } - - /** - * Read a stream with many blocks - */ - @Test - void testReadLongerStream() throws Exception { - 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 - POIFSStream stream = new POIFSStream(fs, 0); - Iterator<ByteBuffer> i = stream.getBlockIterator(); - int count = 0; - while (i.hasNext()) { - ByteBuffer b = i.next(); - if (count == 0) { - b0 = b; - } - if (count == 1) { - b1 = b; - } - if (count == 22) { - b22 = b; - } - - count++; - } - assertEquals(23, count); - - // Check the contents - // 1st block is at 0 - assertNotNull(b0); - assertEquals((byte) 0x9e, b0.get()); - assertEquals((byte) 0x75, b0.get()); - assertEquals((byte) 0x97, b0.get()); - assertEquals((byte) 0xf6, b0.get()); - - // 2nd block is at 1 - assertNotNull(b1); - assertEquals((byte) 0x86, b1.get()); - assertEquals((byte) 0x09, b1.get()); - assertEquals((byte) 0x22, b1.get()); - assertEquals((byte) 0xfb, b1.get()); - - // last block is at 89 - assertNotNull(b22); - assertEquals((byte) 0xfe, b22.get()); - assertEquals((byte) 0xff, b22.get()); - assertEquals((byte) 0x00, b22.get()); - assertEquals((byte) 0x00, b22.get()); - assertEquals((byte) 0x05, b22.get()); - assertEquals((byte) 0x01, b22.get()); - assertEquals((byte) 0x02, b22.get()); - assertEquals((byte) 0x00, b22.get()); - - fs.close(); - } - - /** - * Read a stream with several blocks in a 4096 byte block file - */ - @Test - void testReadStream4096() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("BlockSize4096.zvi")); - - // 0 -> 1 -> 2 -> end - POIFSStream stream = new POIFSStream(fs, 0); - Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertTrue(i.hasNext()); - ByteBuffer b0 = i.next(); - assertTrue(i.hasNext()); - ByteBuffer b1 = i.next(); - assertTrue(i.hasNext()); - ByteBuffer b2 = i.next(); - assertFalse(i.hasNext()); - - // Check the contents of the 1st block - assertEquals((byte) 0x9E, b0.get()); - assertEquals((byte) 0x75, b0.get()); - assertEquals((byte) 0x97, b0.get()); - assertEquals((byte) 0xF6, b0.get()); - assertEquals((byte) 0xFF, b0.get()); - assertEquals((byte) 0x21, b0.get()); - assertEquals((byte) 0xD2, b0.get()); - assertEquals((byte) 0x11, b0.get()); - - // Check the contents of the 2nd block - assertEquals((byte) 0x00, b1.get()); - assertEquals((byte) 0x00, b1.get()); - assertEquals((byte) 0x03, b1.get()); - assertEquals((byte) 0x00, b1.get()); - assertEquals((byte) 0x00, b1.get()); - assertEquals((byte) 0x00, b1.get()); - assertEquals((byte) 0x00, b1.get()); - assertEquals((byte) 0x00, b1.get()); - - // Check the contents of the 3rd block - assertEquals((byte) 0x6D, b2.get()); - assertEquals((byte) 0x00, b2.get()); - assertEquals((byte) 0x00, b2.get()); - assertEquals((byte) 0x00, b2.get()); - assertEquals((byte) 0x03, b2.get()); - assertEquals((byte) 0x00, b2.get()); - assertEquals((byte) 0x46, b2.get()); - assertEquals((byte) 0x00, b2.get()); - - fs.close(); - } - - /** - * Craft a nasty file with a loop, and ensure we don't get stuck - */ - @Test - void testReadFailsOnLoop() throws Exception { - 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); - - // Now try to read - POIFSStream stream = new POIFSStream(fs, 0); - Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertTrue(i.hasNext()); - - // 1st read works - i.next(); - assertTrue(i.hasNext()); - - // 2nd read works - i.next(); - assertTrue(i.hasNext()); - - // 3rd read works - i.next(); - assertTrue(i.hasNext()); - - // 4th read blows up as it loops back to 0 - assertThrows(RuntimeException.class, i::next, "Loop should have been detected but wasn't!"); - assertTrue(i.hasNext()); - - fs.close(); - } - - /** - * Tests that we can load some streams that are - * stored in the mini stream. - */ - @Test - void testReadMiniStreams() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - POIFSMiniStore ministore = fs.getMiniStore(); - - // 178 -> 179 -> 180 -> end - POIFSStream stream = new POIFSStream(ministore, 178); - Iterator<ByteBuffer> i = stream.getBlockIterator(); - assertTrue(i.hasNext()); - ByteBuffer b178 = i.next(); - assertTrue(i.hasNext()); - ByteBuffer b179 = i.next(); - assertTrue(i.hasNext()); - ByteBuffer b180 = i.next(); - assertFalse(i.hasNext()); - - // Check the contents of the 1st block - assertEquals((byte) 0xfe, b178.get()); - assertEquals((byte) 0xff, b178.get()); - assertEquals((byte) 0x00, b178.get()); - assertEquals((byte) 0x00, b178.get()); - assertEquals((byte) 0x05, b178.get()); - assertEquals((byte) 0x01, b178.get()); - assertEquals((byte) 0x02, b178.get()); - assertEquals((byte) 0x00, b178.get()); - - // And the 2nd - assertEquals((byte) 0x6c, b179.get()); - assertEquals((byte) 0x00, b179.get()); - assertEquals((byte) 0x00, b179.get()); - assertEquals((byte) 0x00, b179.get()); - assertEquals((byte) 0x28, b179.get()); - assertEquals((byte) 0x00, b179.get()); - assertEquals((byte) 0x00, b179.get()); - assertEquals((byte) 0x00, b179.get()); - - // And the 3rd - assertEquals((byte) 0x30, b180.get()); - assertEquals((byte) 0x00, b180.get()); - assertEquals((byte) 0x00, b180.get()); - assertEquals((byte) 0x00, b180.get()); - assertEquals((byte) 0x00, b180.get()); - assertEquals((byte) 0x00, b180.get()); - assertEquals((byte) 0x00, b180.get()); - assertEquals((byte) 0x80, b180.get()); - - fs.close(); - } - - /** - * Writing the same amount of data as before - */ - @Test - void testReplaceStream() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - - byte[] data = new byte[512]; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (i % 256); - } - - // 98 is actually the last block in a two block stream... - POIFSStream stream = new POIFSStream(fs, 98); - stream.updateContents(data); - - // 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 less data than before, some blocks will need - * to be freed - */ - @Test - void testReplaceStreamWithLess() throws Exception { - 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]); - } - } - } - - /** - * Writes more data than before, new blocks will be needed - */ - @Test - void testReplaceStreamWithMore() throws Exception { - 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); - } - } - - /** - * Writes to a new stream in the file - */ - @Test - void testWriteNewStream() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - - // 100 is our first free one - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); - 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)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104)); - - - // Add a single block one - byte[] data = new byte[512]; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (i % 256); - } - - POIFSStream stream = new POIFSStream(fs); - stream.updateContents(data); - - // Check it was allocated properly - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104)); - - // And check the contents - 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(1, count); - - - // And a multi block one - data = new byte[512 * 3]; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (i % 256); - } - - stream = new POIFSStream(fs); - stream.updateContents(data); - - // Check it was allocated properly - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100)); - assertEquals(102, fs.getNextBlock(101)); - assertEquals(103, fs.getNextBlock(102)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(103)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104)); - - // And check the contents - it = stream.getBlockIterator(); - 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); - - // Free it - stream.free(); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(100)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(101)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(102)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(103)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(104)); - - fs.close(); - } - - /** - * Writes to a new stream in the file, where we've not enough - * free blocks so new FAT segments will need to be allocated - * to support this - */ - @Test - void testWriteNewStreamExtraFATs() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); - - // Allocate almost all the blocks - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(100)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(127)); - for (int i = 100; i < 127; i++) { - fs.setNextBlock(i, POIFSConstants.END_OF_CHAIN); - } - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(127)); - assertTrue(fs.getBATBlockAndIndex(0).getBlock().hasFreeSectors()); - - - // Write a 3 block stream - byte[] data = new byte[512 * 3]; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (i % 256); - } - POIFSStream stream = new POIFSStream(fs); - stream.updateContents(data); - - // Check we got another BAT - 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)); - assertEquals(129, fs.getNextBlock(127)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(128)); - assertEquals(130, fs.getNextBlock(129)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(130)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(131)); - - fs.close(); - } - - /** - * Replaces data in an existing stream, with a bit - * more data than before, in a 4096 byte block file - */ - @Test - void testWriteStream4096() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi")); - - // 0 -> 1 -> 2 -> end - assertEquals(1, fs.getNextBlock(0)); - assertEquals(2, fs.getNextBlock(1)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2)); - assertEquals(4, fs.getNextBlock(3)); - - // First free one is at 15 - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(14)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(15)); - - - // Write a 5 block file - byte[] data = new byte[4096 * 5]; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (i % 256); - } - POIFSStream stream = new POIFSStream(fs, 0); - stream.updateContents(data); - - - // Check it - assertEquals(1, fs.getNextBlock(0)); - assertEquals(2, fs.getNextBlock(1)); - assertEquals(15, fs.getNextBlock(2)); // Jumps - assertEquals(4, fs.getNextBlock(3)); // Next stream - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(14)); - assertEquals(16, fs.getNextBlock(15)); // Continues - assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(16)); // Ends - assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(17)); // Free - - // Check the contents too - 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(5, count); - - fs.close(); - } - - /** - * Tests that we can write into the mini stream - */ - @Test - void testWriteMiniStreams() throws Exception { - try (InputStream is = _inst.openResourceAsStream("BlockSize512.zvi"); - POIFSFileSystem fs = new POIFSFileSystem(is)) { - - POIFSMiniStore ministore = fs.getMiniStore(); - - // 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); - assertThrows(NoSuchElementException.class, () -> ministore.getBlockAt(184), "Block 184 should be off the end of the list"); - - 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)); - - } - } - - /** - * Craft a nasty file with a loop, and ensure we don't get stuck - */ - @Test - void testWriteFailsOnLoop() throws Exception { - 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 - POIFSStream stream1 = new POIFSStream(fs, 0); - assertThrows(IllegalStateException.class, - () -> stream1.updateContents(new byte[512 * 4]), "Loop should have been detected but wasn't!"); - - // 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); - - POIFSStream stream2 = new POIFSStream(fs, 0); - assertThrows(IllegalStateException.class, - () -> stream2.updateContents(new byte[512]), "Loop should have been detected but wasn't!"); - } - } - - /** - * Tests adding a new stream, writing and reading it. - */ - @Test - void testReadWriteNewStream() throws Exception { - 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()); - assertThrows(IllegalStateException.class, stream::getBlockIterator, - "Shouldn't be able to get an iterator before writing"); - - // 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(data[i], read[i], "Wrong value at " + 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()); - } - } - - /** - * Writes a stream, then replaces it - */ - @Test - void testWriteThenReplace() throws Exception { - POIFSFileSystem fs = new POIFSFileSystem(); - - // Starts empty, other that Properties and BAT - 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)); - - // Write something that uses a main stream - byte[] main4106 = new byte[4106]; - main4106[0] = -10; - main4106[4105] = -11; - 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)); - assertEquals(3, bat.getValueAt(2)); - assertEquals(4, bat.getValueAt(3)); - assertEquals(5, bat.getValueAt(4)); - assertEquals(6, bat.getValueAt(5)); - assertEquals(7, bat.getValueAt(6)); - assertEquals(8, bat.getValueAt(7)); - assertEquals(9, bat.getValueAt(8)); - assertEquals(10, bat.getValueAt(9)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(10)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11)); - - DocumentEntry normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - assertEquals(4106, normal.getSize()); - assertEquals(4106, ((DocumentNode) normal).getProperty().getSize()); - - - // Replace with one still big enough for a main stream, but one block smaller - byte[] main4096 = new byte[4096]; - main4096[0] = -10; - main4096[4095] = -11; - - DocumentOutputStream nout = new DocumentOutputStream(normal); - nout.write(main4096); - nout.close(); - - // Will have dropped to 8 - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); - assertEquals(3, bat.getValueAt(2)); - assertEquals(4, bat.getValueAt(3)); - assertEquals(5, bat.getValueAt(4)); - assertEquals(6, bat.getValueAt(5)); - assertEquals(7, bat.getValueAt(6)); - assertEquals(8, bat.getValueAt(7)); - assertEquals(9, bat.getValueAt(8)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(9)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(10)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11)); - - normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - assertEquals(4096, normal.getSize()); - assertEquals(4096, ((DocumentNode) normal).getProperty().getSize()); - - - // Write and check - fs = writeOutAndReadBack(fs); - bat = fs.getBATBlockAndIndex(0).getBlock(); - - // No change after write - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); // Properties - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); - assertEquals(3, bat.getValueAt(2)); - assertEquals(4, bat.getValueAt(3)); - assertEquals(5, bat.getValueAt(4)); - assertEquals(6, bat.getValueAt(5)); - assertEquals(7, bat.getValueAt(6)); - assertEquals(8, bat.getValueAt(7)); - assertEquals(9, bat.getValueAt(8)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(9)); // End of Normal - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(10)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11)); - - normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - assertEquals(4096, normal.getSize()); - assertEquals(4096, ((DocumentNode) normal).getProperty().getSize()); - - - // Make longer, take 1 block at the end - normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - nout = new DocumentOutputStream(normal); - nout.write(main4106); - nout.close(); - - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); - assertEquals(3, bat.getValueAt(2)); - assertEquals(4, bat.getValueAt(3)); - assertEquals(5, bat.getValueAt(4)); - assertEquals(6, bat.getValueAt(5)); - assertEquals(7, bat.getValueAt(6)); - assertEquals(8, bat.getValueAt(7)); - assertEquals(9, bat.getValueAt(8)); - assertEquals(10, bat.getValueAt(9)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(10)); // Normal - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12)); - - normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - assertEquals(4106, normal.getSize()); - assertEquals(4106, ((DocumentNode) normal).getProperty().getSize()); - - - // 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 DocumentOutputStream(normal); - nout.write(mini); - nout.close(); - - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(2)); // SBAT - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); // Mini Stream - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(4)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(5)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(6)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(7)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(8)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(9)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(10)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(11)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12)); - - normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - assertEquals(7, normal.getSize()); - assertEquals(7, ((DocumentNode) normal).getProperty().getSize()); - - - // Finally back to big again - nout = new DocumentOutputStream(normal); - nout.write(main4096); - nout.close(); - - // Will keep the mini stream, now empty - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(2)); // SBAT - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); // Mini Stream - assertEquals(5, bat.getValueAt(4)); - assertEquals(6, bat.getValueAt(5)); - assertEquals(7, bat.getValueAt(6)); - assertEquals(8, bat.getValueAt(7)); - assertEquals(9, bat.getValueAt(8)); - assertEquals(10, bat.getValueAt(9)); - assertEquals(11, bat.getValueAt(10)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(11)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(13)); - - normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - assertEquals(4096, normal.getSize()); - assertEquals(4096, ((DocumentNode) normal).getProperty().getSize()); - - - // Save, re-load, re-check - fs = writeOutAndReadBack(fs); - bat = fs.getBATBlockAndIndex(0).getBlock(); - - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(2)); // SBAT - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3)); // Mini Stream - assertEquals(5, bat.getValueAt(4)); - assertEquals(6, bat.getValueAt(5)); - assertEquals(7, bat.getValueAt(6)); - assertEquals(8, bat.getValueAt(7)); - assertEquals(9, bat.getValueAt(8)); - assertEquals(10, bat.getValueAt(9)); - assertEquals(11, bat.getValueAt(10)); - assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(11)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(12)); - assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(13)); - - normal = (DocumentEntry) fs.getRoot().getEntry("Normal"); - assertEquals(4096, normal.getSize()); - assertEquals(4096, ((DocumentNode) normal).getProperty().getSize()); - - 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(expectedBAT, foundBAT, "Wrong number of BATs"); - assertEquals(expectedXBAT, foundXBAT, "Wrong number of XBATs with " + expectedBAT + " BATs"); - } - - 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 - 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 - 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); - assertThrows(IndexOutOfBoundsException.class, () -> fs.getBATBlockAndIndex(140), - "Should only be one BAT, but a 2nd was found"); - - // 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); - assertThrows(IndexOutOfBoundsException.class, () -> ministore.getBATBlockAndIndex(256), - "Should only be two SBATs, but a 3rd was found"); - - // 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); - assertThrows(IndexOutOfBoundsException.class, () -> fs.getBATBlockAndIndex(1040), - "Should only be one BAT, but a 2nd was found"); - - // 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); - assertThrows(IndexOutOfBoundsException.class, () -> ministore.getBATBlockAndIndex(1024), - "Should only be one SBAT, but a 2nd was found"); - - // 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 - 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 - 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 - 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 - 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()); - assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(128), "Should only be one BAT"); - 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()); - assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(109 * 128), "Should only be 109 BATs"); - - // 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(free > 0, "Had: " + free); - - assertFalse(fs1.getBATBlockAndIndex(109 * 128 - 1).getBlock().hasFreeSectors()); - assertTrue(fs1.getBATBlockAndIndex(110 * 128 - 1).getBlock().hasFreeSectors()); - assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(110 * 128), "Should only be 110 BATs"); - 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()); - assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(236 * 128), "Should only be 236 BATs"); - assertBATCount(fs1, 236, 1); - - - // Ask for another, will get our 2nd XBAT - free = fs1.getFreeBlock(); - assertTrue(free > 0, "Had: " + free); - - assertFalse(fs1.getBATBlockAndIndex(236 * 128 - 1).getBlock().hasFreeSectors()); - assertTrue(fs1.getBATBlockAndIndex(237 * 128 - 1).getBlock().hasFreeSectors()); - assertThrows(IndexOutOfBoundsException.class, () -> fs1.getBATBlockAndIndex(237 * 128), "Should only be 237 BATs"); - - - // 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()); - assertThrows(IndexOutOfBoundsException.class, () -> fs2.getBATBlockAndIndex(237 * 128), "Should only be 237 BATs"); - - // All done - fs2.close(); - } - - /** - * Test that we can correctly get the list of directory - * entries, and the details on the files in them - */ - @Test - 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 - 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 - 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 - 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)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(9)); // End of normal4096 - - assertEquals(11, fs5.getNextBlock(10)); - assertEquals(12, fs5.getNextBlock(11)); - assertEquals(13, fs5.getNextBlock(12)); - assertEquals(14, fs5.getNextBlock(13)); - assertEquals(15, fs5.getNextBlock(14)); - assertEquals(16, fs5.getNextBlock(15)); - assertEquals(17, fs5.getNextBlock(16)); - assertEquals(18, fs5.getNextBlock(17)); - assertEquals(19, fs5.getNextBlock(18)); - assertEquals(20, fs5.getNextBlock(19)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(20)); // End of normal5124 - - assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(21)); // Mini Stream FAT - assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(22)); // Mini Stream data - assertEquals(POIFSConstants.END_OF_CHAIN, fs5.getNextBlock(23)); // Properties #2 - assertEquals(POIFSConstants.UNUSED_BLOCK, fs5.getNextBlock(24)); - - - // Check some data - assertEquals(1, fs5.getRoot().getEntryCount()); - testDir = (DirectoryEntry) fs5.getRoot().getEntry("Test Directory"); - assertEquals(3, testDir.getEntryCount()); - - miniDoc = (DocumentEntry) testDir.getEntry("Mini"); - assertContentsMatches(mini, miniDoc); - - normDoc = (DocumentEntry) testDir.getEntry("Normal4096"); - assertContentsMatches(main4096, normDoc); - - normDoc = (DocumentEntry) testDir.getEntry("Normal5124"); - assertContentsMatches(main5124, normDoc); - - - // Delete a couple of streams - miniDoc.delete(); - normDoc.delete(); - - - // Check - will have un-used sectors now - POIFSFileSystem fs6 = writeOutAndReadBack(fs5); - fs5.close(); - - assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(0)); // Props back in 1 block - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs6.getNextBlock(1)); - - assertEquals(3, fs6.getNextBlock(2)); - assertEquals(4, fs6.getNextBlock(3)); - assertEquals(5, fs6.getNextBlock(4)); - assertEquals(6, fs6.getNextBlock(5)); - assertEquals(7, fs6.getNextBlock(6)); - assertEquals(8, fs6.getNextBlock(7)); - assertEquals(9, fs6.getNextBlock(8)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(9)); // End of normal4096 - - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(10)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(11)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(12)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(13)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(14)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(15)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(16)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(17)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(18)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(19)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(20)); - - assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(21)); // Mini Stream FAT - assertEquals(POIFSConstants.END_OF_CHAIN, fs6.getNextBlock(22)); // Mini Stream data - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(23)); // Properties gone - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(24)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs6.getNextBlock(25)); - - // All done - fs6.close(); - } - - @Test - void addBeforeWrite() throws IOException { - POIFSFileSystem fs1 = new POIFSFileSystem(); - DocumentEntry miniDoc; - DocumentEntry normDoc; - HeaderBlock hdr; - - // Initially has Properties + BAT but nothing else - assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(1)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(2)); - - hdr = writeOutAndReadHeader(fs1); - // No mini stream, and no xbats - // Will have fat then properties stream - assertEquals(1, hdr.getBATCount()); - assertEquals(1, hdr.getBATArray()[0]); - assertEquals(0, hdr.getPropertyStart()); - assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getSBATStart()); - assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getXBATIndex()); - assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE * 3, fs1.size()); - fs1.close(); - - // Get a clean filesystem to start with - fs1 = new POIFSFileSystem(); - - // Put our test files in a non-standard place - DirectoryEntry parentDir = fs1.createDirectory("Parent Directory"); - DirectoryEntry testDir = parentDir.createDirectory("Test Directory"); - - - // Add to the mini stream - byte[] mini = new byte[]{42, 0, 1, 2, 3, 4, 42}; - testDir.createDocument("Mini", new ByteArrayInputStream(mini)); - - // Add to the main stream - byte[] main4096 = new byte[4096]; - main4096[0] = -10; - main4096[4095] = -11; - testDir.createDocument("Normal4096", new ByteArrayInputStream(main4096)); - - - // Check the mini stream was added, then the main stream - assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(0)); - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs1.getNextBlock(1)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(2)); // Mini Fat - assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(3)); // Mini Stream - assertEquals(5, fs1.getNextBlock(4)); // Main Stream - assertEquals(6, fs1.getNextBlock(5)); - assertEquals(7, fs1.getNextBlock(6)); - assertEquals(8, fs1.getNextBlock(7)); - assertEquals(9, fs1.getNextBlock(8)); - assertEquals(10, fs1.getNextBlock(9)); - assertEquals(11, fs1.getNextBlock(10)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs1.getNextBlock(11)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs1.getNextBlock(12)); - assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE * 13, fs1.size()); - - - // Check that we can read the right data pre-write - miniDoc = (DocumentEntry) testDir.getEntry("Mini"); - assertContentsMatches(mini, miniDoc); - - normDoc = (DocumentEntry) testDir.getEntry("Normal4096"); - assertContentsMatches(main4096, normDoc); - - - // Write, read, check - hdr = writeOutAndReadHeader(fs1); - POIFSFileSystem fs2 = writeOutAndReadBack(fs1); - fs1.close(); - - // Check the header details - will have the sbat near the start, - // then the properties at the end - assertEquals(1, hdr.getBATCount()); - assertEquals(1, hdr.getBATArray()[0]); - assertEquals(2, hdr.getSBATStart()); - assertEquals(0, hdr.getPropertyStart()); - assertEquals(POIFSConstants.END_OF_CHAIN, hdr.getXBATIndex()); - - // Check the block allocation is unchanged, other than - // the properties stream going in at the end - assertEquals(12, fs2.getNextBlock(0)); // Properties - assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs2.getNextBlock(1)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(2)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(3)); - assertEquals(5, fs2.getNextBlock(4)); - assertEquals(6, fs2.getNextBlock(5)); - assertEquals(7, fs2.getNextBlock(6)); - assertEquals(8, fs2.getNextBlock(7)); - assertEquals(9, fs2.getNextBlock(8)); - assertEquals(10, fs2.getNextBlock(9)); - assertEquals(11, fs2.getNextBlock(10)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(11)); - assertEquals(POIFSConstants.END_OF_CHAIN, fs2.getNextBlock(12)); - assertEquals(POIFSConstants.UNUSED_BLOCK, fs2.getNextBlock(13)); - assertEquals(POIFSConstants.SMALLER_BIG_BLOCK_SIZE * 14, fs2.size()); - - - // Check the data - DirectoryEntry fsRoot = fs2.getRoot(); - assertEquals(1, fsRoot.getEntryCount()); - - parentDir = (DirectoryEntry) fsRoot.getEntry("Parent Directory"); - assertEquals(1, parentDir.getEntryCount()); - - testDir = (DirectoryEntry) parentDir.getEntry("Test Directory"); - assertEquals(2, testDir.getEntryCount()); - - miniDoc = (DocumentEntry) testDir.getEntry("Mini"); - assertContentsMatches(mini, miniDoc); - - normDoc = (DocumentEntry) testDir.getEntry("Normal4096"); - assertContentsMatches(main4096, normDoc); - - - // Add one more stream to each, then save and re-load - byte[] mini2 = new byte[]{-42, 0, -1, -2, -3, -4, -42}; - testDir.createDocument("Mini2", new ByteArrayInputStream(mini2)); - - // Add to the main stream - byte[] main4106 = new byte[4106]; - main4106[0] = 41; - main4106[4105] = 42; - testDir.createDocument("Normal4106", new ByteArrayInputStream(main4106)); - - - // Recheck the data in all 4 streams - POIFSFileSystem fs3 = writeOutAndReadBack(fs2); - fs2.close(); - - fsRoot = fs3.getRoot(); - assertEquals(1, fsRoot.getEntryCount()); - - parentDir = (DirectoryEntry) fsRoot.getEntry("Parent Directory"); - assertEquals(1, parentDir.getEntryCount()); - - testDir = (DirectoryEntry) parentDir.getEntry("Test Directory"); - assertEquals(4, testDir.getEntryCount()); - - miniDoc = (DocumentEntry) testDir.getEntry("Mini"); - assertContentsMatches(mini, miniDoc); - - miniDoc = (DocumentEntry) testDir.getEntry("Mini2"); - assertContentsMatches(mini2, miniDoc); - - normDoc = (DocumentEntry) testDir.getEntry("Normal4106"); - assertContentsMatches(main4106, normDoc); - - // All done - fs3.close(); - } - - @Test - void readZeroLengthEntries() throws IOException { - POIFSFileSystem fs = new POIFSFileSystem(_inst.getFile("only-zero-byte-streams.ole2")); - DirectoryNode testDir = fs.getRoot(); - assertEquals(3, testDir.getEntryCount()); - DocumentEntry entry; - - entry = (DocumentEntry) testDir.getEntry("test-zero-1"); - assertNotNull(entry); - assertEquals(0, entry.getSize()); - - entry = (DocumentEntry) testDir.getEntry("test-zero-2"); - assertNotNull(entry); - assertEquals(0, entry.getSize()); - - entry = (DocumentEntry) testDir.getEntry("test-zero-3"); - assertNotNull(entry); - assertEquals(0, entry.getSize()); - - // Check properties, all have zero length, no blocks - PropertyTable props = fs._get_property_table(); - assertEquals(POIFSConstants.END_OF_CHAIN, props.getRoot().getStartBlock()); - for (Property prop : props.getRoot()) { - assertEquals("test-zero-", prop.getName().substring(0, 10)); - assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock()); - } - - // All done - fs.close(); - } - - @Test - void writeZeroLengthEntries() throws IOException { - POIFSFileSystem fs1 = new POIFSFileSystem(); - DirectoryNode testDir = fs1.getRoot(); - DocumentEntry miniDoc; - DocumentEntry normDoc; - DocumentEntry emptyDoc; - - // Add mini and normal sized entries to start - byte[] mini2 = new byte[]{-42, 0, -1, -2, -3, -4, -42}; - testDir.createDocument("Mini2", new ByteArrayInputStream(mini2)); - - // Add to the main stream - byte[] main4106 = new byte[4106]; - main4106[0] = 41; - main4106[4105] = 42; - testDir.createDocument("Normal4106", new ByteArrayInputStream(main4106)); - - // Now add some empty ones - byte[] empty = new byte[0]; - testDir.createDocument("empty-1", new ByteArrayInputStream(empty)); - testDir.createDocument("empty-2", new ByteArrayInputStream(empty)); - testDir.createDocument("empty-3", new ByteArrayInputStream(empty)); - - // Check - miniDoc = (DocumentEntry) testDir.getEntry("Mini2"); - assertContentsMatches(mini2, miniDoc); - - normDoc = (DocumentEntry) testDir.getEntry("Normal4106"); - assertContentsMatches(main4106, normDoc); - - emptyDoc = (DocumentEntry) testDir.getEntry("empty-1"); - assertContentsMatches(empty, emptyDoc); - - emptyDoc = (DocumentEntry) testDir.getEntry("empty-2"); - assertContentsMatches(empty, emptyDoc); - - emptyDoc = (DocumentEntry) testDir.getEntry("empty-3"); - assertContentsMatches(empty, emptyDoc); - - // Look at the properties entry, and check the empty ones - // have zero size and no start block - PropertyTable props = fs1._get_property_table(); - Iterator<Property> propsIt = props.getRoot().getChildren(); - - Property prop = propsIt.next(); - assertEquals("Mini2", prop.getName()); - assertEquals(0, prop.getStartBlock()); - assertEquals(7, prop.getSize()); - - prop = propsIt.next(); - assertEquals("Normal4106", prop.getName()); - assertEquals(4, prop.getStartBlock()); // BAT, Props, SBAT, MIni - assertEquals(4106, prop.getSize()); - - prop = propsIt.next(); - assertEquals("empty-1", prop.getName()); - assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock()); - assertEquals(0, prop.getSize()); - - prop = propsIt.next(); - assertEquals("empty-2", prop.getName()); - assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock()); - assertEquals(0, prop.getSize()); - - prop = propsIt.next(); - assertEquals("empty-3", prop.getName()); - assertEquals(POIFSConstants.END_OF_CHAIN, prop.getStartBlock()); - assertEquals(0, prop.getSize()); - - - // Save and re-check - POIFSFileSystem fs2 = writeOutAndReadBack(fs1); - fs1.close(); - testDir = fs2.getRoot(); - - miniDoc = (DocumentEntry) testDir.getEntry("Mini2"); - assertContentsMatches(mini2, miniDoc); - - normDoc = (DocumentEntry) testDir.getEntry("Normal4106"); - assertContentsMatches(main4106, normDoc); - - emptyDoc = (DocumentEntry) testDir.getEntry("empty-1"); - assertContentsMatches(empty, emptyDoc); - - emptyDoc = (DocumentEntry) testDir.getEntry("empty-2"); - assertContentsMatches(empty, emptyDoc); - - emptyDoc = (DocumentEntry) testDir.getEntry("empty-3"); - assertContentsMatches(empty, emptyDoc); - - // Check that a mini-stream was assigned, with one block used - assertEquals(3, testDir.getProperty().getStartBlock()); - assertEquals(64, testDir.getProperty().getSize()); - - // All done - fs2.close(); - } - - /** - * Test that we can read a file with POIFS, create a new POIFS instance, - * write it out, read it with POIFS, and see the original data - */ - @Test - void POIFSReadCopyWritePOIFSRead() throws IOException { - File testFile = POIDataSamples.getSpreadSheetInstance().getFile("Simple.xls"); - POIFSFileSystem src = new POIFSFileSystem(testFile); - byte[] wbDataExp = IOUtils.toByteArray(src.createDocumentInputStream("Workbook")); - - POIFSFileSystem nfs = new POIFSFileSystem(); - EntryUtils.copyNodes(src.getRoot(), nfs.getRoot()); - src.close(); - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - nfs.writeFilesystem(bos); - nfs.close(); - - POIFSFileSystem pfs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray())); - byte[] wbDataAct = IOUtils.toByteArray(pfs.createDocumentInputStream("Workbook")); - - assertThat(wbDataExp, equalTo(wbDataAct)); - pfs.close(); - } - - /** - * Ensure that you can recursively delete directories and their - * contents - */ - @Test - void RecursiveDelete() throws IOException { - File testFile = POIDataSamples.getSpreadSheetInstance().getFile("SimpleMacro.xls"); - POIFSFileSystem src = new POIFSFileSystem(testFile); - - // Starts out with 5 entries: - // _VBA_PROJECT_CUR - // SummaryInformation <(0x05)SummaryInformation> - // DocumentSummaryInformation <(0x05)DocumentSummaryInformation> - // Workbook - // CompObj <(0x01)CompObj> - assertEquals(5, _countChildren(src._get_property_table().getRoot())); - assertEquals(5, src.getRoot().getEntryCount()); - - // Grab the VBA project root - DirectoryEntry vbaProj = (DirectoryEntry) src.getRoot().getEntry("_VBA_PROJECT_CUR"); - assertEquals(3, vbaProj.getEntryCount()); - // Can't delete yet, has stuff - assertFalse(vbaProj.delete()); - // Recursively delete - _recursiveDeletee(vbaProj); - - // Entries gone - assertEquals(4, _countChildren(src._get_property_table().getRoot())); - assertEquals(4, src.getRoot().getEntryCount()); - - // Done - src.close(); - } - - private void _recursiveDeletee(Entry entry) throws IOException { - if (entry.isDocumentEntry()) { - assertTrue(entry.delete()); - return; - } - - DirectoryEntry dir = (DirectoryEntry) entry; - String[] names = dir.getEntryNames().toArray(new String[dir.getEntryCount()]); - for (String name : names) { - Entry ce = dir.getEntry(name); - _recursiveDeletee(ce); - } - assertTrue(dir.delete()); - } - - @SuppressWarnings("unused") - private int _countChildren(DirectoryProperty p) { - int count = 0; - for (Property cp : p) { - count++; - } - return count; - } - - /** - * To ensure we can create a file >2gb in size, as well as to - * extend existing files past the 2gb boundary. - * <p> - * Note that to run this test, you will require 2.5+gb of free - * space on your TMP/TEMP partition/disk - * <p> - * Note that to run this test, you need to be able to mmap 2.5+gb - * files, which may need bigger kernel.shmmax and vm.max_map_count - * settings on Linux. - * <p> - * TODO Fix this to work... - */ - @Test - @Disabled("Work in progress test for #60670") - void creationAndExtensionPast2GB() throws Exception { - File big = TempFile.createTempFile("poi-test-", ".ole2"); - assumeTrue(big.getFreeSpace() > 2.5 * 1024 * 1024 * 1024, - "2.5gb of free space is required on your tmp/temp partition/disk to run large file tests"); - System.out.println("Slow, memory heavy test in progress...."); - - int s100mb = 100 * 1024 * 1024; - int s512mb = 512 * 1024 * 1024; - long s2gb = 2L * 1024 * 1024 * 1024; - DocumentEntry entry; - POIFSFileSystem fs; - - // Create a just-sub 2gb file - fs = POIFSFileSystem.create(big); - for (int i = 0; i < 19; i++) { - fs.createDocument(new DummyDataInputStream(s100mb), "Entry" + i); - } - fs.writeFilesystem(); - fs.close(); - - // Extend it past the 2gb mark - fs = new POIFSFileSystem(big, false); - for (int i = 0; i < 19; i++) { - entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i); - assertNotNull(entry); - assertEquals(s100mb, entry.getSize()); - } - - fs.createDocument(new DummyDataInputStream(s512mb), "Bigger"); - fs.writeFilesystem(); - fs.close(); - - // Check it still works - fs = new POIFSFileSystem(big, false); - for (int i = 0; i < 19; i++) { - entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i); - assertNotNull(entry); - assertEquals(s100mb, entry.getSize()); - } - entry = (DocumentEntry) fs.getRoot().getEntry("Bigger"); - assertNotNull(entry); - assertEquals(s512mb, entry.getSize()); - - // Tidy - fs.close(); - assertTrue(big.delete()); - - - // Create a >2gb file - fs = POIFSFileSystem.create(big); - for (int i = 0; i < 4; i++) { - fs.createDocument(new DummyDataInputStream(s512mb), "Entry" + i); - } - fs.writeFilesystem(); - fs.close(); - - // Read it - fs = new POIFSFileSystem(big, false); - for (int i = 0; i < 4; i++) { - entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i); - assertNotNull(entry); - assertEquals(s512mb, entry.getSize()); - } - - // Extend it - fs.createDocument(new DummyDataInputStream(s512mb), "Entry4"); - fs.writeFilesystem(); - fs.close(); - - // Check it worked - fs = new POIFSFileSystem(big, false); - for (int i = 0; i < 5; i++) { - entry = (DocumentEntry) fs.getRoot().getEntry("Entry" + i); - assertNotNull(entry); - assertEquals(s512mb, entry.getSize()); - } - - // Tidy - fs.close(); - assertTrue(big.delete()); - - // Create a file with a 2gb entry - fs = POIFSFileSystem.create(big); - fs.createDocument(new DummyDataInputStream(s100mb), "Small"); - // TODO Check we get a helpful error about the max size - fs.createDocument(new DummyDataInputStream(s2gb), "Big"); - } - - 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() { - if (size >= maxSize) return -1; - size++; - return (int) (size % 128); - } - - public int read(byte[] b) { - return read(b, 0, b.length); - } - - 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 < sz; i++) { - b[i + offset] = (byte) ((size + i) % 128); - } - size += sz; - return sz; - } - } - - @Disabled("Takes a long time to run") - @Test - void performance() throws Exception { - int iterations = 200;//1_000; - - System.out.println("NPOI:"); - long start = System.currentTimeMillis(); - - for (int i = 0; i < iterations; i++) { - - try (InputStream inputStream = POIDataSamples.getHSMFInstance().openResourceAsStream("lots-of-recipients.msg"); - POIFSFileSystem srcFileSystem = new POIFSFileSystem(inputStream); - POIFSFileSystem destFileSystem = new POIFSFileSystem()) { - - copyAllEntries(srcFileSystem.getRoot(), destFileSystem.getRoot()); - - File file = File.createTempFile("npoi", ".dat"); - try (OutputStream outputStream = new FileOutputStream(file)) { - destFileSystem.writeFilesystem(outputStream); - } - - assertTrue(file.delete()); - if (i % 10 == 0) System.out.print("."); - } - } - - System.out.println(); - System.out.println("NPOI took: " + (System.currentTimeMillis() - start)); - - System.out.println(); - System.out.println(); - } - - private static void copyAllEntries(DirectoryEntry srcDirectory, DirectoryEntry destDirectory) throws IOException { - Iterator<Entry> iterator = srcDirectory.getEntries(); - - while (iterator.hasNext()) { - Entry entry = iterator.next(); - - if (entry.isDirectoryEntry()) { - DirectoryEntry childDest = destDirectory.createDirectory(entry.getName()); - copyAllEntries((DirectoryEntry) entry, childDest); - - } else { - DocumentEntry srcEntry = (DocumentEntry) entry; - - try (InputStream inputStream = new DocumentInputStream(srcEntry)) { - destDirectory.createDocument(entry.getName(), inputStream); - } - } - } - } - -} |