More BATBlock related methods for identifying size and list offsets, plus tests
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1051791 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c3c4e4f2f7
commit
c0a0faf9c5
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.poifs.common.POIFSBigBlockSize;
|
||||
import org.apache.poi.poifs.common.POIFSConstants;
|
||||
@ -194,7 +195,6 @@ public final class BATBlock extends BigBlock {
|
||||
*
|
||||
* @return the number of BATBlocks needed
|
||||
*/
|
||||
|
||||
public static int calculateStorageRequirements(final POIFSBigBlockSize bigBlockSize, final int entryCount)
|
||||
{
|
||||
int _entries_per_block = bigBlockSize.getBATEntriesPerBlock();
|
||||
@ -209,14 +209,62 @@ public final class BATBlock extends BigBlock {
|
||||
*
|
||||
* @return the number of XBATBlocks needed
|
||||
*/
|
||||
|
||||
public static int calculateXBATStorageRequirements(final POIFSBigBlockSize bigBlockSize, final int entryCount)
|
||||
{
|
||||
int _entries_per_xbat_block = bigBlockSize.getXBATEntriesPerBlock();
|
||||
return (entryCount + _entries_per_xbat_block - 1)
|
||||
/ _entries_per_xbat_block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the maximum size of a file which is addressable given the
|
||||
* number of FAT (BAT and XBAT) sectors specified.
|
||||
* The actual file size will be between [size of fatCount-1 blocks] and
|
||||
* [size of fatCount blocks].
|
||||
* For 512 byte block sizes, this means we may over-estimate by up to 65kb.
|
||||
* For 4096 byte block sizes, this means we may over-estimate by up to 4mb
|
||||
*/
|
||||
public static int calculateMaximumSize(final POIFSBigBlockSize bigBlockSize,
|
||||
final int numBAT, final int numXBAT) {
|
||||
int size = 1; // Header isn't FAT addressed
|
||||
size += (numBAT * bigBlockSize.getBATEntriesPerBlock());
|
||||
size += (numXBAT * bigBlockSize.getXBATEntriesPerBlock());
|
||||
return size * bigBlockSize.getBigBlockSize();
|
||||
}
|
||||
public static int calculateMaximumSize(final HeaderBlock header)
|
||||
{
|
||||
return calculateMaximumSize(header.getBigBlockSize(), header.getBATCount(), header.getXBATCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the BATBlock that handles the specified offset,
|
||||
* and the relative index within it.
|
||||
* The List of BATBlocks must be in sequential order
|
||||
*/
|
||||
public static BATBlockAndIndex getBATBlockAndIndex(final int offset,
|
||||
final HeaderBlock header, final List<BATBlock> blocks) {
|
||||
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, blocks.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,
|
||||
blocks.get(header.getBATCount() + whichXBAT)
|
||||
);
|
||||
}
|
||||
|
||||
private void setXBATChain(final POIFSBigBlockSize bigBlockSize, int chainIndex)
|
||||
{
|
||||
int _entries_per_xbat_block = bigBlockSize.getXBATEntriesPerBlock();
|
||||
@ -277,5 +325,21 @@ public final class BATBlock extends BigBlock {
|
||||
}
|
||||
|
||||
/* ********** END extension of BigBlock ********** */
|
||||
} // end public class BATBlock
|
||||
|
||||
|
||||
public static class BATBlockAndIndex {
|
||||
private final int index;
|
||||
private final BATBlock block;
|
||||
private BATBlockAndIndex(int index, BATBlock block) {
|
||||
this.index = index;
|
||||
this.block = block;
|
||||
}
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
public BATBlock getBlock() {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,10 @@ package org.apache.poi.poifs.storage;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.poifs.common.POIFSConstants;
|
||||
|
||||
@ -208,4 +211,175 @@ public final class TestBATBlock extends TestCase {
|
||||
public void testGetXBATChainOffset() {
|
||||
assertEquals(508, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS.getNextXBATChainOffset());
|
||||
}
|
||||
|
||||
public void testCalculateMaximumSize() throws Exception {
|
||||
// Zero fat blocks isn't technically valid, but it'd be header only
|
||||
assertEquals(
|
||||
512,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 0, 0)
|
||||
);
|
||||
assertEquals(
|
||||
4096,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 0, 0)
|
||||
);
|
||||
|
||||
// A single FAT block can address 128/1024 blocks
|
||||
assertEquals(
|
||||
512 + 512*128,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 1, 0)
|
||||
);
|
||||
assertEquals(
|
||||
4096 + 4096*1024,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 1, 0)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
512 + 4*512*128,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 4, 0)
|
||||
);
|
||||
assertEquals(
|
||||
4096 + 4*4096*1024,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 4, 0)
|
||||
);
|
||||
|
||||
// Once we get into XBAT blocks, they address a little bit less
|
||||
assertEquals(
|
||||
512 + 109*512*128,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 109, 0)
|
||||
);
|
||||
assertEquals(
|
||||
4096 + 109*4096*1024,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 109, 0)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
512 + 109*512*128 + 512*127,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 109, 1)
|
||||
);
|
||||
assertEquals(
|
||||
4096 + 109*4096*1024 + 4096*1023,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 109, 1)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
512 + 109*512*128 + 3*512*127,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 109, 3)
|
||||
);
|
||||
assertEquals(
|
||||
4096 + 109*4096*1024 + 3*4096*1023,
|
||||
BATBlock.calculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 109, 3)
|
||||
);
|
||||
}
|
||||
|
||||
public void testGetBATBlockAndIndex() throws Exception {
|
||||
HeaderBlock header = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
|
||||
List<BATBlock> blocks = new ArrayList<BATBlock>();
|
||||
int offset;
|
||||
|
||||
|
||||
// First, try a one BAT block file
|
||||
header.setBATCount(1);
|
||||
blocks.add(
|
||||
BATBlock.createBATBlock(header.getBigBlockSize(), ByteBuffer.allocate(512))
|
||||
);
|
||||
|
||||
offset = 0;
|
||||
assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 1;
|
||||
assertEquals(1, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 127;
|
||||
assertEquals(127, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
|
||||
// Now go for one with multiple BAT blocks
|
||||
header.setBATCount(2);
|
||||
blocks.add(
|
||||
BATBlock.createBATBlock(header.getBigBlockSize(), ByteBuffer.allocate(512))
|
||||
);
|
||||
|
||||
offset = 0;
|
||||
assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 127;
|
||||
assertEquals(127, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 128;
|
||||
assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 129;
|
||||
assertEquals(1, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
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);
|
||||
offset = 0;
|
||||
assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 126;
|
||||
assertEquals(126, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
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() ));
|
||||
|
||||
offset = 128;
|
||||
assertEquals(1, 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, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
|
||||
// Check with the bigger block size too
|
||||
header = new HeaderBlock(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS);
|
||||
|
||||
offset = 0;
|
||||
assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 1022;
|
||||
assertEquals(1022, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
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() ));
|
||||
|
||||
offset = 1024;
|
||||
assertEquals(1, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
// Biggr block size, back to real BATs
|
||||
header.setBATCount(2);
|
||||
|
||||
offset = 0;
|
||||
assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 1022;
|
||||
assertEquals(1022, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 1023;
|
||||
assertEquals(1023, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(0, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
|
||||
offset = 1024;
|
||||
assertEquals(0, BATBlock.getBATBlockAndIndex(offset, header, blocks).getIndex());
|
||||
assertEquals(1, blocks.indexOf( BATBlock.getBATBlockAndIndex(offset, header, blocks).getBlock() ));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user