[github-182] Fix root property size calculation. Thanks to netmackan. This closes #182

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1878721 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2020-06-10 17:30:28 +00:00
parent ff67cdf116
commit 0181d2abd9
3 changed files with 271 additions and 188 deletions

View File

@ -252,7 +252,7 @@ public class POIFSMiniStore extends BlockStore
if (!sbat.hasFreeSectors()) { if (!sbat.hasFreeSectors()) {
blocksUsed += _filesystem.getBigBlockSizeDetails().getBATEntriesPerBlock(); blocksUsed += _filesystem.getBigBlockSizeDetails().getBATEntriesPerBlock();
} else { } else {
blocksUsed += sbat.getUsedSectors(false); blocksUsed += sbat.getOccupiedSize();
} }
} }
// Set the size on the root in terms of the number of SBAT blocks // Set the size on the root in terms of the number of SBAT blocks

View File

@ -192,6 +192,27 @@ public final class BATBlock implements BlockWritable {
return usedSectors; return usedSectors;
} }
/**
* How much of this block is occupied?.
* This counts the number of sectors up and including the last used sector.
* Note that this is different from {@link #getUsedSectors(boolean)} which
* could be smaller as it does not count unused sectors where there are
* used ones after it (i.e. fragmentation).
*
* @since POI 5.0.0
*/
public int getOccupiedSize() {
int usedSectors = _values.length;
for (int k = _values.length - 1; k >= 0; k--) {
if(_values[k] == POIFSConstants.UNUSED_BLOCK) {
usedSectors--;
} else {
break;
}
}
return usedSectors;
}
public int getValueAt(int relativeOffset) { public int getValueAt(int relativeOffset) {
if(relativeOffset >= _values.length) { if(relativeOffset >= _values.length) {
throw new ArrayIndexOutOfBoundsException( throw new ArrayIndexOutOfBoundsException(
@ -201,6 +222,7 @@ public final class BATBlock implements BlockWritable {
} }
return _values[relativeOffset]; return _values[relativeOffset];
} }
public void setValueAt(int relativeOffset, int value) { public void setValueAt(int relativeOffset, int value) {
int oldValue = _values[relativeOffset]; int oldValue = _values[relativeOffset];
_values[relativeOffset] = value; _values[relativeOffset] = value;
@ -221,6 +243,7 @@ public final class BATBlock implements BlockWritable {
public void setOurBlockIndex(int index) { public void setOurBlockIndex(int index) {
this.ourBlockIndex = index; this.ourBlockIndex = index;
} }
/** /**
* Retrieve where in the file we live * Retrieve where in the file we live
*/ */
@ -237,7 +260,6 @@ public final class BATBlock implements BlockWritable {
* @exception IOException on problems writing to the specified * @exception IOException on problems writing to the specified
* stream * stream
*/ */
public void writeBlocks(final OutputStream stream) throws IOException { public void writeBlocks(final OutputStream stream) throws IOException {
// Save it out // Save it out
stream.write( serialize() ); stream.write( serialize() );

View File

@ -176,6 +176,67 @@ public final class TestBATBlock {
assertEquals(1023, block4096.getUsedSectors(true)); assertEquals(1023, block4096.getUsedSectors(true));
} }
@Test
public void testOccupiedSize() {
POIFSBigBlockSize b512 = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;
POIFSBigBlockSize b4096 = POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS;
// Try first with 512 block sizes, which can hold 128 entries
BATBlock block512 = BATBlock.createEmptyBATBlock(b512, false);
assertTrue(block512.hasFreeSectors());
assertEquals(0, block512.getUsedSectors(false));
// Allocate a few
block512.setValueAt(0, 42);
block512.setValueAt(10, 42);
block512.setValueAt(20, 42);
assertTrue(block512.hasFreeSectors());
assertEquals(21, block512.getOccupiedSize());
// Release one in the middle should not lower size
block512.setValueAt(10, POIFSConstants.UNUSED_BLOCK);
assertTrue(block512.hasFreeSectors());
assertEquals(21, block512.getOccupiedSize());
// Release the last one should lower the size
block512.setValueAt(20, POIFSConstants.UNUSED_BLOCK);
assertTrue(block512.hasFreeSectors());
assertEquals(1, block512.getOccupiedSize());
// Release first one should lower the size
block512.setValueAt(0, POIFSConstants.UNUSED_BLOCK);
assertTrue(block512.hasFreeSectors());
assertEquals(0, block512.getOccupiedSize());
// Set the last one
block512.setValueAt(127, 42);
assertTrue(block512.hasFreeSectors());
assertEquals(128, block512.getOccupiedSize());
block512.setValueAt(126, 42);
assertTrue(block512.hasFreeSectors());
assertEquals(128, block512.getOccupiedSize());
block512.setValueAt(127, POIFSConstants.UNUSED_BLOCK);
assertTrue(block512.hasFreeSectors());
assertEquals(127, block512.getOccupiedSize());
// Allocate all
for (int i = 0; i < b512.getBATEntriesPerBlock(); i++) {
block512.setValueAt(i, 82);
}
// Check
assertFalse(block512.hasFreeSectors());
assertEquals(128, block512.getOccupiedSize());
// Release some in the beginning should not lower size
block512.setValueAt(0, POIFSConstants.UNUSED_BLOCK);
block512.setValueAt(1, POIFSConstants.UNUSED_BLOCK);
block512.setValueAt(13, POIFSConstants.UNUSED_BLOCK);
assertTrue(block512.hasFreeSectors());
assertEquals(128, block512.getOccupiedSize());
}
@Test @Test
public void testGetBATBlockAndIndex() { public void testGetBATBlockAndIndex() {
HeaderBlock header = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); HeaderBlock header = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);