diff options
author | Nick Burch <nick@apache.org> | 2011-05-12 21:00:04 +0000 |
---|---|---|
committer | Nick Burch <nick@apache.org> | 2011-05-12 21:00:04 +0000 |
commit | 8362b74f90cb31d09bf5ab3e31dcad23510f4e1e (patch) | |
tree | b6f98e10420dbf97ad3f0bc9d554f67316819eaa /src | |
parent | 6c2d2ffe7fd9af4ff0614752736f164f338d937c (diff) | |
download | poi-8362b74f90cb31d09bf5ab3e31dcad23510f4e1e.tar.gz poi-8362b74f90cb31d09bf5ab3e31dcad23510f4e1e.zip |
Finish NPOIFS support for writing to mini streams where the big block stream needs extending, and unit tests
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1102458 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
4 files changed, 164 insertions, 7 deletions
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index cc0b65671f..db3adb4e1b 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ <changes> <release version="3.8-beta3" date="2011-??-??"> + <action dev="poi-developers" type="add">NPOIFS Mini Streams now support extending the underlying big block stream to fit more data</action> <action dev="poi-developers" type="fix">51148 - XWPFDocument now properly tracks paragraphs and tables when adding/removing them</action> <action dev="poi-developers" type="fix">51153 - Correct sizing of LbsDataSubRecord with unused padding fields</action> <action dev="poi-developers" type="fix">51143 - NameCommentRecord correction for writing non ASCII strings</action> diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java index 6d43c3f714..33d0b25418 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java @@ -69,6 +69,9 @@ public class NPOIFSMiniStore extends BlockStore it.next(); } ByteBuffer dataBlock = it.next(); + if(dataBlock == null) { + throw new IndexOutOfBoundsException("Big block " + bigBlockNumber + " outside stream"); + } // Position ourselves, and take a slice dataBlock.position( @@ -83,9 +86,35 @@ public class NPOIFSMiniStore extends BlockStore * Load the block, extending the underlying stream if needed */ protected ByteBuffer createBlockIfNeeded(final int offset) throws IOException { - // TODO Extend the stream if needed - // TODO Needs append support on the underlying stream - return getBlockAt(offset); + // Try to get it without extending the stream + try { + return getBlockAt(offset); + } catch(IndexOutOfBoundsException e) { + // Need to extend the stream + // TODO Replace this with proper append support + // For now, do the extending by hand... + + // Ask for another block + int newBigBlock = _filesystem.getFreeBlock(); + _filesystem.createBlockIfNeeded(newBigBlock); + + // Tack it onto the end of our chain + ChainLoopDetector loopDetector = _filesystem.getChainLoopDetector(); + int block = _mini_stream.getStartBlock(); + while(true) { + loopDetector.claim(block); + int next = _filesystem.getNextBlock(block); + if(next == POIFSConstants.END_OF_CHAIN) { + break; + } + block = next; + } + _filesystem.setNextBlock(block, newBigBlock); + _filesystem.setNextBlock(newBigBlock, POIFSConstants.END_OF_CHAIN); + + // Now try again to get it + return createBlockIfNeeded(offset); + } } /** diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSMiniStore.java b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSMiniStore.java index 8f495903b7..90daf160aa 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSMiniStore.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSMiniStore.java @@ -18,6 +18,7 @@ package org.apache.poi.poifs.filesystem; import java.nio.ByteBuffer; +import java.util.Iterator; import junit.framework.TestCase; @@ -245,7 +246,80 @@ public final class TestNPOIFSMiniStore extends TestCase { * big blocks that make up the ministream as needed */ public void testCreateBlockIfNeeded() throws Exception { - // TODO Add underlying implementation - // TODO Add unit test + NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi")); + NPOIFSMiniStore ministore = fs.getMiniStore(); + + // 178 -> 179 -> 180, 181+ is free + assertEquals(179 , ministore.getNextBlock(178)); + assertEquals(180 , ministore.getNextBlock(179)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(180)); + for(int i=181; i<256; i++) { + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); + } + + // However, the ministore data only covers blocks to 183 + for(int i=0; i<=183; i++) { + ministore.getBlockAt(i); + } + try { + ministore.getBlockAt(184); + fail("No block at 184"); + } catch(IndexOutOfBoundsException e) {} + + // The ministore itself is made up of 23 big blocks + Iterator<ByteBuffer> it = new NPOIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator(); + int count = 0; + while(it.hasNext()) { + count++; + it.next(); + } + assertEquals(23, count); + + // Ask it to get block 184 with creating, it will do + ministore.createBlockIfNeeded(184); + + // The ministore should be one big block bigger now + it = new NPOIFSStream(fs, fs.getRoot().getProperty().getStartBlock()).getBlockIterator(); + count = 0; + while(it.hasNext()) { + count++; + it.next(); + } + assertEquals(24, count); + + // The mini block block counts now run to 191 + for(int i=0; i<=191; i++) { + ministore.getBlockAt(i); + } + try { + ministore.getBlockAt(192); + fail("No block at 192"); + } catch(IndexOutOfBoundsException e) {} + + + // Now try writing through to 192, check that the SBAT and blocks are there + byte[] data = new byte[15*64]; + NPOIFSStream stream = new NPOIFSStream(ministore, 178); + stream.updateContents(data); + + // Check now + 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(185 , ministore.getNextBlock(184)); + assertEquals(186 , ministore.getNextBlock(185)); + assertEquals(187 , ministore.getNextBlock(186)); + assertEquals(188 , ministore.getNextBlock(187)); + assertEquals(189 , ministore.getNextBlock(188)); + assertEquals(190 , ministore.getNextBlock(189)); + assertEquals(191 , ministore.getNextBlock(190)); + assertEquals(192 , ministore.getNextBlock(191)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(192)); + for(int i=193; i<256; i++) { + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(i)); + } } } diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java index ca9dd6677b..256037100c 100644 --- a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSStream.java @@ -731,8 +731,61 @@ public final class TestNPOIFSStream extends TestCase { assertEquals((byte)0x04, b182.get(1)); - // Write lots, so it needs another big block - // TODO + // Write lots, so it needs another big block + ministore.getBlockAt(183); + try { + ministore.getBlockAt(184); + fail("Block 184 should be off the end of the list"); + } catch(IndexOutOfBoundsException e) {} + + data = new byte[64*6 + 12]; + for(int i=0; i<data.length; i++) { + data[i] = (byte)(i+1); + } + stream = new NPOIFSStream(ministore, 178); + stream.updateContents(data); + + // Should have added 2 more blocks to the chain + assertEquals(179, ministore.getNextBlock(178)); + assertEquals(180, ministore.getNextBlock(179)); + assertEquals(181, ministore.getNextBlock(180)); + assertEquals(182, ministore.getNextBlock(181)); + assertEquals(183, ministore.getNextBlock(182)); + assertEquals(184, ministore.getNextBlock(183)); + assertEquals(POIFSConstants.END_OF_CHAIN, ministore.getNextBlock(184)); + assertEquals(POIFSConstants.UNUSED_BLOCK, ministore.getNextBlock(185)); + + // Block 184 should exist + ministore.getBlockAt(183); + ministore.getBlockAt(184); + ministore.getBlockAt(185); + + // Check contents + stream = new NPOIFSStream(ministore, 178); + it = stream.getBlockIterator(); + b178 = it.next(); + b179 = it.next(); + b180 = it.next(); + b181 = it.next(); + b182 = it.next(); + ByteBuffer b183 = it.next(); + ByteBuffer b184 = it.next(); + assertEquals(false, it.hasNext()); + + assertEquals((byte)0x01, b178.get(0)); + assertEquals((byte)0x02, b178.get(1)); + assertEquals((byte)0x41, b179.get(0)); + assertEquals((byte)0x42, b179.get(1)); + assertEquals((byte)0x81, b180.get(0)); + assertEquals((byte)0x82, b180.get(1)); + assertEquals((byte)0xc1, b181.get(0)); + assertEquals((byte)0xc2, b181.get(1)); + assertEquals((byte)0x01, b182.get(0)); + assertEquals((byte)0x02, b182.get(1)); + assertEquals((byte)0x41, b183.get(0)); + assertEquals((byte)0x42, b183.get(1)); + assertEquals((byte)0x81, b184.get(0)); + assertEquals((byte)0x82, b184.get(1)); } /** |