use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class NPOIFSFileSystem method readBAT.
private void readBAT(int batAt, ChainLoopDetector loopDetector) throws IOException {
loopDetector.claim(batAt);
ByteBuffer fatData = getBlockAt(batAt);
BATBlock bat = BATBlock.createBATBlock(bigBlockSize, fatData);
bat.setOurBlockIndex(batAt);
_bat_blocks.add(bat);
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class TestPOIFSFileSystem method testBATandXBAT.
/**
* Tests that we can write and read a file that contains XBATs
* as well as regular BATs.
* However, because a file needs to be at least 6.875mb big
* to have an XBAT in it, we don't have a test one. So, generate it.
*/
public void testBATandXBAT() throws Exception {
byte[] hugeStream = new byte[8 * 1024 * 1024];
OPOIFSFileSystem fs = new OPOIFSFileSystem();
fs.getRoot().createDocument("BIG", new ByteArrayInputStream(hugeStream));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
fs.writeFilesystem(baos);
byte[] fsData = baos.toByteArray();
// Check the header was written properly
InputStream inp = new ByteArrayInputStream(fsData);
HeaderBlock header = new HeaderBlock(inp);
assertEquals(109 + 21, header.getBATCount());
assertEquals(1, header.getXBATCount());
// We should have 21 BATs in the XBAT
ByteBuffer xbatData = ByteBuffer.allocate(512);
xbatData.put(fsData, (1 + header.getXBATIndex()) * 512, 512);
xbatData.position(0);
BATBlock xbat = BATBlock.createBATBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, xbatData);
for (int i = 0; i < 21; i++) {
assertTrue(xbat.getValueAt(i) != POIFSConstants.UNUSED_BLOCK);
}
for (int i = 21; i < 127; i++) {
assertEquals(POIFSConstants.UNUSED_BLOCK, xbat.getValueAt(i));
}
assertEquals(POIFSConstants.END_OF_CHAIN, xbat.getValueAt(127));
// Load the blocks and check with that
RawDataBlockList blockList = new RawDataBlockList(inp, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
// Header not counted
assertEquals(fsData.length / 512, blockList.blockCount() + 1);
new BlockAllocationTableReader(header.getBigBlockSize(), header.getBATCount(), header.getBATArray(), header.getXBATCount(), header.getXBATIndex(), blockList);
// Header not counted
assertEquals(fsData.length / 512, blockList.blockCount() + 1);
// Now load it and check
fs = null;
fs = new OPOIFSFileSystem(new ByteArrayInputStream(fsData));
DirectoryNode root = fs.getRoot();
assertEquals(1, root.getEntryCount());
DocumentNode big = (DocumentNode) root.getEntry("BIG");
assertEquals(hugeStream.length, big.getSize());
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class OPOIFSFileSystem method writeFilesystem.
/**
* Write the filesystem out
*
* @param stream the OutputStream to which the filesystem will be
* written
*
* @exception IOException thrown on errors writing to the stream
*/
public void writeFilesystem(final OutputStream stream) throws IOException {
// get the property table ready
_property_table.preWrite();
// create the small block store, and the SBAT
SmallBlockTableWriter sbtw = new SmallBlockTableWriter(bigBlockSize, _documents, _property_table.getRoot());
// create the block allocation table
BlockAllocationTableWriter bat = new BlockAllocationTableWriter(bigBlockSize);
// create a list of BATManaged objects: the documents plus the
// property table and the small block table
List<Object> bm_objects = new ArrayList<Object>();
bm_objects.addAll(_documents);
bm_objects.add(_property_table);
bm_objects.add(sbtw);
bm_objects.add(sbtw.getSBAT());
// walk the list, allocating space for each and assigning each
// a starting block number
Iterator<Object> iter = bm_objects.iterator();
while (iter.hasNext()) {
BATManaged bmo = (BATManaged) iter.next();
int block_count = bmo.countBlocks();
if (block_count != 0) {
bmo.setStartBlock(bat.allocateSpace(block_count));
} else {
// Either the BATManaged object is empty or its data
// is composed of SmallBlocks; in either case,
// allocating space in the BAT is inappropriate
}
}
// allocate space for the block allocation table and take its
// starting block
int batStartBlock = bat.createBlocks();
// get the extended block allocation table blocks
HeaderBlockWriter header_block_writer = new HeaderBlockWriter(bigBlockSize);
BATBlock[] xbat_blocks = header_block_writer.setBATBlocks(bat.countBlocks(), batStartBlock);
// set the property table start block
header_block_writer.setPropertyStart(_property_table.getStartBlock());
// set the small block allocation table start block
header_block_writer.setSBATStart(sbtw.getSBAT().getStartBlock());
// set the small block allocation table block count
header_block_writer.setSBATBlockCount(sbtw.getSBATBlockCount());
// the header is now properly initialized. Make a list of
// writers (the header block, followed by the documents, the
// property table, the small block store, the small block
// allocation table, the block allocation table, and the
// extended block allocation table blocks)
List<Object> writers = new ArrayList<Object>();
writers.add(header_block_writer);
writers.addAll(_documents);
writers.add(_property_table);
writers.add(sbtw);
writers.add(sbtw.getSBAT());
writers.add(bat);
for (int j = 0; j < xbat_blocks.length; j++) {
writers.add(xbat_blocks[j]);
}
// now, write everything out
iter = writers.iterator();
while (iter.hasNext()) {
BlockWritable writer = (BlockWritable) iter.next();
writer.writeBlocks(stream);
}
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class NPOIFSFileSystem method syncWithDataSource.
/**
* Has our in-memory objects write their state
* to their backing blocks
*/
private void syncWithDataSource() throws IOException {
// Mini Stream + SBATs first, as mini-stream details have
// to be stored in the Root Property
_mini_store.syncWithDataSource();
// Properties
NPOIFSStream propStream = new NPOIFSStream(this, _header.getPropertyStart());
_property_table.preWrite();
_property_table.write(propStream);
// _header.setPropertyStart has been updated on write ...
// HeaderBlock
HeaderBlockWriter hbw = new HeaderBlockWriter(_header);
hbw.writeBlock(getBlockAt(-1));
// BATs
for (BATBlock bat : _bat_blocks) {
ByteBuffer block = getBlockAt(bat.getOurBlockIndex());
BlockAllocationTableWriter.writeBlock(bat, block);
}
// XBats
for (BATBlock bat : _xbat_blocks) {
ByteBuffer block = getBlockAt(bat.getOurBlockIndex());
BlockAllocationTableWriter.writeBlock(bat, block);
}
}
use of org.apache.poi.poifs.storage.BATBlock in project poi by apache.
the class NPOIFSFileSystem method readCoreContents.
/**
* Read and process the PropertiesTable and the
* FAT / XFAT blocks, so that we're ready to
* work with the file
*/
private void readCoreContents() throws IOException {
// Grab the block size
bigBlockSize = _header.getBigBlockSize();
// Each block should only ever be used by one of the
// FAT, XFAT or Property Table. Ensure it does
ChainLoopDetector loopDetector = getChainLoopDetector();
// Read the FAT blocks
for (int fatAt : _header.getBATArray()) {
readBAT(fatAt, loopDetector);
}
// Work out how many FAT blocks remain in the XFATs
int remainingFATs = _header.getBATCount() - _header.getBATArray().length;
// Now read the XFAT blocks, and the FATs within them
BATBlock xfat;
int nextAt = _header.getXBATIndex();
for (int i = 0; i < _header.getXBATCount(); i++) {
loopDetector.claim(nextAt);
ByteBuffer fatData = getBlockAt(nextAt);
xfat = BATBlock.createBATBlock(bigBlockSize, fatData);
xfat.setOurBlockIndex(nextAt);
nextAt = xfat.getValueAt(bigBlockSize.getXBATEntriesPerBlock());
_xbat_blocks.add(xfat);
// Process all the (used) FATs from this XFAT
int xbatFATs = Math.min(remainingFATs, bigBlockSize.getXBATEntriesPerBlock());
for (int j = 0; j < xbatFATs; j++) {
int fatAt = xfat.getValueAt(j);
if (fatAt == POIFSConstants.UNUSED_BLOCK || fatAt == POIFSConstants.END_OF_CHAIN)
break;
readBAT(fatAt, loopDetector);
}
remainingFATs -= xbatFATs;
}
// We're now able to load steams
// Use this to read in the properties
_property_table = new NPropertyTable(_header, this);
// Finally read the Small Stream FAT (SBAT) blocks
BATBlock sfat;
List<BATBlock> sbats = new ArrayList<BATBlock>();
_mini_store = new NPOIFSMiniStore(this, _property_table.getRoot(), sbats, _header);
nextAt = _header.getSBATStart();
for (int i = 0; i < _header.getSBATCount() && nextAt != POIFSConstants.END_OF_CHAIN; i++) {
loopDetector.claim(nextAt);
ByteBuffer fatData = getBlockAt(nextAt);
sfat = BATBlock.createBATBlock(bigBlockSize, fatData);
sfat.setOurBlockIndex(nextAt);
sbats.add(sfat);
nextAt = getNextBlock(nextAt);
}
}
Aggregations