From d6578850ab9a4e7bbafb6eff103dea2f10af735e Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Wed, 29 Dec 2010 01:05:01 +0000 Subject: [PATCH] XBAT logic in NPOIFS was incorrect - it's a chain of doubly indirect, not singly indirect BATs. Start to correct git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1053495 13f79535-47bb-0310-9956-ffa450edef68 --- .../filesystem/NDocumentInputStream.java | 2 - .../poifs/filesystem/NPOIFSFileSystem.java | 24 +++++++--- .../apache/poi/poifs/storage/BATBlock.java | 48 ++++++++++--------- .../poi/poifs/storage/TestBATBlock.java | 32 ++++++------- 4 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java b/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java index 52c06f808b..2595ba0259 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java +++ b/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java @@ -29,8 +29,6 @@ import org.apache.poi.util.LittleEndianInput; /** * This class provides methods to read a DocumentEntry managed by a * {@link POIFSFileSystem} instance. - * - * @author Marc Johnson (mjohnson at apache dot org) */ public final class NDocumentInputStream extends InputStream implements LittleEndianInput { /** returned by read operations if we're at end of document */ diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java index a397136c20..9f491313ec 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java @@ -77,6 +77,7 @@ public class NPOIFSFileSystem extends BlockStore private NPOIFSMiniStore _mini_store; private NPropertyTable _property_table; + private List _xbat_blocks; private List _bat_blocks; private HeaderBlock _header; private DirectoryNode _root; @@ -98,6 +99,7 @@ public class NPOIFSFileSystem extends BlockStore _header = new HeaderBlock(bigBlockSize); _property_table = new NPropertyTable(_header); _mini_store = new NPOIFSMiniStore(this, _property_table.getRoot(), new ArrayList(), _header); + _xbat_blocks = new ArrayList(); _bat_blocks = new ArrayList(); _root = null; } @@ -264,14 +266,10 @@ public class NPOIFSFileSystem extends BlockStore // Read the FAT blocks for(int fatAt : _header.getBATArray()) { - loopDetector.claim(fatAt); - ByteBuffer fatData = getBlockAt(fatAt); - BATBlock bat = BATBlock.createBATBlock(bigBlockSize, fatData); - bat.setOurBlockIndex(fatAt); - _bat_blocks.add(bat); + readBAT(fatAt, loopDetector); } - // Now read the XFAT blocks + // Now read the XFAT blocks, and the FATs within them BATBlock xfat; int nextAt = _header.getXBATIndex(); for(int i=0; i<_header.getXBATCount(); i++) { @@ -280,8 +278,13 @@ public class NPOIFSFileSystem extends BlockStore xfat = BATBlock.createBATBlock(bigBlockSize, fatData); xfat.setOurBlockIndex(nextAt); nextAt = xfat.getValueAt(bigBlockSize.getXBATEntriesPerBlock()); + _xbat_blocks.add(xfat); - _bat_blocks.add(xfat); + for(int j=0; j bats) { POIFSBigBlockSize bigBlockSize = header.getBigBlockSize(); - // Are we in the BAT or XBAT range - int batRangeEndsAt = bigBlockSize.getBATEntriesPerBlock() * - header.getBATCount(); - - if(offset < batRangeEndsAt) { - int whichBAT = (int)Math.floor(offset / bigBlockSize.getBATEntriesPerBlock()); - int index = offset % bigBlockSize.getBATEntriesPerBlock(); - return new BATBlockAndIndex( index, bats.get(whichBAT) ); - } - - // XBATs hold slightly less - int relOffset = offset - batRangeEndsAt; - int whichXBAT = (int)Math.floor(relOffset / bigBlockSize.getXBATEntriesPerBlock()); - int index = relOffset % bigBlockSize.getXBATEntriesPerBlock(); - return new BATBlockAndIndex( - index, - bats.get(header.getBATCount() + whichXBAT) - ); + int whichBAT = (int)Math.floor(offset / bigBlockSize.getBATEntriesPerBlock()); + int index = offset % bigBlockSize.getBATEntriesPerBlock(); + return new BATBlockAndIndex( index, bats.get(whichBAT) ); } /** diff --git a/src/testcases/org/apache/poi/poifs/storage/TestBATBlock.java b/src/testcases/org/apache/poi/poifs/storage/TestBATBlock.java index 82b49e1154..1ef6cc9394 100644 --- a/src/testcases/org/apache/poi/poifs/storage/TestBATBlock.java +++ b/src/testcases/org/apache/poi/poifs/storage/TestBATBlock.java @@ -242,7 +242,8 @@ public final class TestBATBlock extends TestCase { BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 4, 0) ); - // Once we get into XBAT blocks, they address a little bit less + // One XBAT block holds 127/1023 individual BAT blocks, so they can address + // a fairly hefty amount of space themselves assertEquals( 512 + 109*512*128, BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 109, 0) @@ -253,20 +254,20 @@ public final class TestBATBlock extends TestCase { ); assertEquals( - 512 + 109*512*128 + 512*127, + 512 + 109*512*128 + 512*127*128, BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 109, 1) ); assertEquals( - 4096 + 109*4096*1024 + 4096*1023, + 4096 + 109*4096*1024 + 4096*1023*1024, BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 109, 1) ); assertEquals( - 512 + 109*512*128 + 3*512*127, + 512 + 109*512*128 + 3*512*127*128, BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 109, 3) ); assertEquals( - 4096 + 109*4096*1024 + 3*4096*1023, + 4096 + 109*4096*1024 + 3*4096*1023*1024, BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 109, 3) ); } @@ -319,10 +320,9 @@ public final class TestBATBlock extends TestCase { assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); - // And finally one with XBATs too - // This is a naughty file, but we should be able to cope... - // (We'll decide everything is XBAT not BAT) - header.setBATCount(0); + // The XBAT count makes no difference, as we flatten in memory + header.setBATCount(1); + header.setXBATCount(1); offset = 0; assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); @@ -332,15 +332,15 @@ public final class TestBATBlock extends TestCase { assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); offset = 127; - assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); - assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); + assertEquals(127, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); + assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); offset = 128; - assertEquals(1, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); + assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); offset = 129; - assertEquals(2, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); + assertEquals(1, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); @@ -356,11 +356,11 @@ public final class TestBATBlock extends TestCase { assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); offset = 1023; - assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); - assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); + assertEquals(1023, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); + assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); offset = 1024; - assertEquals(1, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); + assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex()); assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() )); // Biggr block size, back to real BATs -- 2.39.5