Make BATBlock useful for read (was previously write only)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1050770 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2010-12-19 07:17:14 +00:00
parent d9cec1d58c
commit e86e3af3b2
2 changed files with 113 additions and 42 deletions

View File

@ -19,13 +19,12 @@ package org.apache.poi.poifs.storage;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.IntegerField; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
/** /**
* A block of block allocation table entries. BATBlocks are created * A block of block allocation table entries. BATBlocks are created
@ -34,9 +33,18 @@ import org.apache.poi.util.LittleEndianConsts;
* @author Marc Johnson (mjohnson at apache dot org) * @author Marc Johnson (mjohnson at apache dot org)
*/ */
public final class BATBlock extends BigBlock { public final class BATBlock extends BigBlock {
private static final byte _default_value = ( byte ) 0xFF; /**
private IntegerField[] _fields; * For a regular fat block, these are 128 / 1024
private byte[] _data; * next sector values.
* For a XFat (DIFat) block, these are 127 / 1023
* next sector values, then a chaining value.
*/
private int[] _values;
/**
* Does this BATBlock have any free sectors in it?
*/
private boolean _has_free_sectors;
/** /**
* Create a single instance initialized with default values * Create a single instance initialized with default values
@ -47,17 +55,67 @@ public final class BATBlock extends BigBlock {
super(bigBlockSize); super(bigBlockSize);
int _entries_per_block = bigBlockSize.getBATEntriesPerBlock(); int _entries_per_block = bigBlockSize.getBATEntriesPerBlock();
_values = new int[_entries_per_block];
_has_free_sectors = true;
_data = new byte[ bigBlockSize.getBigBlockSize() ]; Arrays.fill(_values, POIFSConstants.UNUSED_BLOCK);
Arrays.fill(_data, _default_value); }
_fields = new IntegerField[ _entries_per_block ];
int offset = 0;
for (int j = 0; j < _entries_per_block; j++) /**
{ * Create a single instance initialized (perhaps partially) with entries
_fields[ j ] = new IntegerField(offset); *
offset += LittleEndianConsts.INT_SIZE; * @param entries the array of block allocation table entries
* @param start_index the index of the first entry to be written
* to the block
* @param end_index the index, plus one, of the last entry to be
* written to the block (writing is for all index
* k, start_index <= k < end_index)
*/
private BATBlock(POIFSBigBlockSize bigBlockSize, final int [] entries,
final int start_index, final int end_index)
{
this(bigBlockSize);
for (int k = start_index; k < end_index; k++) {
_values[k - start_index] = entries[k];
} }
// Do we have any free sectors?
if(end_index - start_index == _values.length) {
recomputeFree();
}
}
private void recomputeFree() {
boolean hasFree = false;
for(int k=0; k<_values.length; k++) {
if(_values[k] == POIFSConstants.UNUSED_BLOCK) {
hasFree = true;
break;
}
}
_has_free_sectors = hasFree;
}
/**
* Create a single BATBlock from the byte buffer, which must hold at least
* one big block of data to be read.
*/
public static BATBlock createBATBlock(final POIFSBigBlockSize bigBlockSize, ByteBuffer data)
{
// Create an empty block
BATBlock block = new BATBlock(bigBlockSize);
// Fill it
byte[] buffer = new byte[LittleEndian.INT_SIZE];
for(int i=0; i<block._values.length; i++) {
data.get(buffer);
block._values[i] = LittleEndian.getInt(buffer);
}
block.recomputeFree();
// All done
return block;
} }
/** /**
@ -68,7 +126,6 @@ public final class BATBlock extends BigBlock {
* *
* @return the newly created array of BATBlocks * @return the newly created array of BATBlocks
*/ */
public static BATBlock [] createBATBlocks(final POIFSBigBlockSize bigBlockSize, final int [] entries) public static BATBlock [] createBATBlocks(final POIFSBigBlockSize bigBlockSize, final int [] entries)
{ {
int block_count = calculateStorageRequirements(bigBlockSize, entries.length); int block_count = calculateStorageRequirements(bigBlockSize, entries.length);
@ -163,28 +220,32 @@ public final class BATBlock extends BigBlock {
private void setXBATChain(final POIFSBigBlockSize bigBlockSize, int chainIndex) private void setXBATChain(final POIFSBigBlockSize bigBlockSize, int chainIndex)
{ {
int _entries_per_xbat_block = bigBlockSize.getXBATEntriesPerBlock(); int _entries_per_xbat_block = bigBlockSize.getXBATEntriesPerBlock();
_fields[ _entries_per_xbat_block ].set(chainIndex, _data); _values[ _entries_per_xbat_block ] = chainIndex;
} }
/** /**
* Create a single instance initialized (perhaps partially) with entries * Does this BATBlock have any free sectors in it, or
* * is it full?
* @param entries the array of block allocation table entries
* @param start_index the index of the first entry to be written
* to the block
* @param end_index the index, plus one, of the last entry to be
* written to the block (writing is for all index
* k, start_index <= k < end_index)
*/ */
public boolean hasFreeSectors() {
return _has_free_sectors;
}
private BATBlock(POIFSBigBlockSize bigBlockSize, final int [] entries, public int getValueAt(int relativeOffset) {
final int start_index, final int end_index) return _values[relativeOffset];
{ }
this(bigBlockSize); public void setValueAt(int relativeOffset, int value) {
for (int k = start_index; k < end_index; k++) int oldValue = _values[relativeOffset];
{ _values[relativeOffset] = value;
_fields[ k - start_index ].set(entries[ k ], _data);
} // Do we need to re-compute the free?
if(value == POIFSConstants.UNUSED_BLOCK) {
_has_free_sectors = true;
return;
}
if(oldValue == POIFSConstants.UNUSED_BLOCK) {
recomputeFree();
}
} }
/* ********** START extension of BigBlock ********** */ /* ********** START extension of BigBlock ********** */
@ -198,11 +259,21 @@ public final class BATBlock extends BigBlock {
* @exception IOException on problems writing to the specified * @exception IOException on problems writing to the specified
* stream * stream
*/ */
void writeData(final OutputStream stream) void writeData(final OutputStream stream)
throws IOException throws IOException
{ {
doWriteData(stream, _data); // Create the empty array
byte[] data = new byte[ bigBlockSize.getBigBlockSize() ];
// Fill in the values
int offset = 0;
for(int i=0; i<_values.length; i++) {
LittleEndian.putInt(data, offset, _values[i]);
offset += LittleEndian.INT_SIZE;
}
// Save it out
stream.write(data);
} }
/* ********** END extension of BigBlock ********** */ /* ********** END extension of BigBlock ********** */

View File

@ -21,8 +21,8 @@ package org.apache.poi.poifs.storage;
/** /**
* Abstract base class of all POIFS block storage classes. All * Abstract base class of all POIFS block storage classes. All
* extensions of BigBlock should write 512 bytes of data when * extensions of BigBlock should write 512 or 4096 bytes of data when
* requested to write their data. * requested to write their data (as per their BigBlockSize).
* *
* This class has package scope, as there is no reason at this time to * This class has package scope, as there is no reason at this time to
* make the class public. * make the class public.