use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class NPOIFSFileSystem method getFreeBlock.
/**
* Finds a free block, and returns its offset.
* This method will extend the file if needed, and if doing
* so, allocate new FAT blocks to address the extra space.
*/
@Override
protected int getFreeBlock() throws IOException {
int numSectors = bigBlockSize.getBATEntriesPerBlock();
// First up, do we have any spare ones?
int offset = 0;
for (BATBlock bat : _bat_blocks) {
if (bat.hasFreeSectors()) {
// Claim one of them and return it
for (int j = 0; j < numSectors; j++) {
int batValue = bat.getValueAt(j);
if (batValue == POIFSConstants.UNUSED_BLOCK) {
// Bingo
return offset + j;
}
}
}
// Move onto the next BAT
offset += numSectors;
}
// If we get here, then there aren't any free sectors
// in any of the BATs, so we need another BAT
BATBlock bat = createBAT(offset, true);
bat.setValueAt(0, POIFSConstants.FAT_SECTOR_BLOCK);
_bat_blocks.add(bat);
// Now store a reference to the BAT in the required place
if (_header.getBATCount() >= 109) {
// Needs to come from an XBAT
BATBlock xbat = null;
for (BATBlock x : _xbat_blocks) {
if (x.hasFreeSectors()) {
xbat = x;
break;
}
}
if (xbat == null) {
// Oh joy, we need a new XBAT too...
xbat = createBAT(offset + 1, false);
// Allocate our new BAT as the first block in the XBAT
xbat.setValueAt(0, offset);
// And allocate the XBAT in the BAT
bat.setValueAt(1, POIFSConstants.DIFAT_SECTOR_BLOCK);
// Will go one place higher as XBAT added in
offset++;
// Chain it
if (_xbat_blocks.size() == 0) {
_header.setXBATStart(offset);
} else {
_xbat_blocks.get(_xbat_blocks.size() - 1).setValueAt(bigBlockSize.getXBATEntriesPerBlock(), offset);
}
_xbat_blocks.add(xbat);
_header.setXBATCount(_xbat_blocks.size());
} else {
// Allocate our BAT in the existing XBAT with space
for (int i = 0; i < bigBlockSize.getXBATEntriesPerBlock(); i++) {
if (xbat.getValueAt(i) == POIFSConstants.UNUSED_BLOCK) {
xbat.setValueAt(i, offset);
break;
}
}
}
} else {
// Store us in the header
int[] newBATs = new int[_header.getBATCount() + 1];
System.arraycopy(_header.getBATArray(), 0, newBATs, 0, newBATs.length - 1);
newBATs[newBATs.length - 1] = offset;
_header.setBATArray(newBATs);
}
_header.setBATCount(_bat_blocks.size());
// The current offset stores us, but the next one is free
return offset + 1;
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class NPOIFSMiniStore method getFreeBlock.
/**
* Finds a free block, and returns its offset.
* This method will extend the file if needed, and if doing
* so, allocate new FAT blocks to address the extra space.
*/
protected int getFreeBlock() throws IOException {
int sectorsPerSBAT = _filesystem.getBigBlockSizeDetails().getBATEntriesPerBlock();
// First up, do we have any spare ones?
int offset = 0;
for (int i = 0; i < _sbat_blocks.size(); i++) {
// Check this one
BATBlock sbat = _sbat_blocks.get(i);
if (sbat.hasFreeSectors()) {
// Claim one of them and return it
for (int j = 0; j < sectorsPerSBAT; j++) {
int sbatValue = sbat.getValueAt(j);
if (sbatValue == POIFSConstants.UNUSED_BLOCK) {
// Bingo
return offset + j;
}
}
}
// Move onto the next SBAT
offset += sectorsPerSBAT;
}
// If we get here, then there aren't any
// free sectors in any of the SBATs
// So, we need to extend the chain and add another
// Create a new BATBlock
BATBlock newSBAT = BATBlock.createEmptyBATBlock(_filesystem.getBigBlockSizeDetails(), false);
int batForSBAT = _filesystem.getFreeBlock();
newSBAT.setOurBlockIndex(batForSBAT);
// Are we the first SBAT?
if (_header.getSBATCount() == 0) {
// Tell the header that we've got our first SBAT there
_header.setSBATStart(batForSBAT);
_header.setSBATBlockCount(1);
} else {
// Find the end of the SBAT stream, and add the sbat in there
ChainLoopDetector loopDetector = _filesystem.getChainLoopDetector();
int batOffset = _header.getSBATStart();
while (true) {
loopDetector.claim(batOffset);
int nextBat = _filesystem.getNextBlock(batOffset);
if (nextBat == POIFSConstants.END_OF_CHAIN) {
break;
}
batOffset = nextBat;
}
// Add it in at the end
_filesystem.setNextBlock(batOffset, batForSBAT);
// And update the count
_header.setSBATBlockCount(_header.getSBATCount() + 1);
}
// Finish allocating
_filesystem.setNextBlock(batForSBAT, POIFSConstants.END_OF_CHAIN);
_sbat_blocks.add(newSBAT);
// Return our first spot
return offset;
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class NPOIFSFileSystem method createBAT.
private BATBlock createBAT(int offset, boolean isBAT) throws IOException {
// Create a new BATBlock
BATBlock newBAT = BATBlock.createEmptyBATBlock(bigBlockSize, !isBAT);
newBAT.setOurBlockIndex(offset);
// Ensure there's a spot in the file for it
ByteBuffer buffer = ByteBuffer.allocate(bigBlockSize.getBigBlockSize());
// Header isn't in BATs
int writeTo = (1 + offset) * bigBlockSize.getBigBlockSize();
_data.write(buffer, writeTo);
// All done
return newBAT;
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class NPOIFSMiniStore method syncWithDataSource.
/**
* Writes the SBATs to their backing blocks, and updates
* the mini-stream size in the properties. Stream size is
* based on full blocks used, not the data within the streams
*/
protected void syncWithDataSource() throws IOException {
int blocksUsed = 0;
for (BATBlock sbat : _sbat_blocks) {
ByteBuffer block = _filesystem.getBlockAt(sbat.getOurBlockIndex());
BlockAllocationTableWriter.writeBlock(sbat, block);
if (!sbat.hasFreeSectors()) {
blocksUsed += _filesystem.getBigBlockSizeDetails().getBATEntriesPerBlock();
} else {
blocksUsed += sbat.getUsedSectors(false);
}
}
// Set the size on the root in terms of the number of SBAT blocks
// RootProperty.setSize does the sbat -> bytes conversion for us
_filesystem._get_property_table().getRoot().setSize(blocksUsed);
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class TestNPOIFSStream method testReadWriteNewStream.
/**
* Tests adding a new stream, writing and reading it.
*/
public void testReadWriteNewStream() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem();
NPOIFSStream stream = new NPOIFSStream(fs);
// Check our filesystem has Properties then BAT
assertEquals(2, fs.getFreeBlock());
BATBlock bat = fs.getBATBlockAndIndex(0).getBlock();
assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(2));
// Check the stream as-is
assertEquals(POIFSConstants.END_OF_CHAIN, stream.getStartBlock());
try {
stream.getBlockIterator();
fail("Shouldn't be able to get an iterator before writing");
} catch (IllegalStateException e) {
}
// Write in two blocks
byte[] data = new byte[512 + 20];
for (int i = 0; i < 512; i++) {
data[i] = (byte) (i % 256);
}
for (int i = 512; i < data.length; i++) {
data[i] = (byte) (i % 256 + 100);
}
stream.updateContents(data);
// Check now
assertEquals(4, fs.getFreeBlock());
bat = fs.getBATBlockAndIndex(0).getBlock();
assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(0));
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, bat.getValueAt(1));
assertEquals(3, bat.getValueAt(2));
assertEquals(POIFSConstants.END_OF_CHAIN, bat.getValueAt(3));
assertEquals(POIFSConstants.UNUSED_BLOCK, bat.getValueAt(4));
Iterator<ByteBuffer> it = stream.getBlockIterator();
assertEquals(true, it.hasNext());
ByteBuffer b = it.next();
byte[] read = new byte[512];
b.get(read);
for (int i = 0; i < read.length; i++) {
assertEquals("Wrong value at " + i, data[i], read[i]);
}
assertEquals(true, it.hasNext());
b = it.next();
read = new byte[512];
b.get(read);
for (int i = 0; i < 20; i++) {
assertEquals(data[i + 512], read[i]);
}
for (int i = 20; i < read.length; i++) {
assertEquals(0, read[i]);
}
assertEquals(false, it.hasNext());
fs.close();
}
Aggregations