Search in sources :

Example 6 with BATBlock

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;
}
Also used : BATBlock(org.apache.poi.poifs.storage.BATBlock)

Example 7 with BATBlock

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;
}
Also used : BATBlock(org.apache.poi.poifs.storage.BATBlock)

Example 8 with BATBlock

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;
}
Also used : BATBlock(org.apache.poi.poifs.storage.BATBlock) ByteBuffer(java.nio.ByteBuffer)

Example 9 with BATBlock

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);
}
Also used : BATBlock(org.apache.poi.poifs.storage.BATBlock) ByteBuffer(java.nio.ByteBuffer)

Example 10 with BATBlock

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();
}
Also used : BATBlock(org.apache.poi.poifs.storage.BATBlock) ByteBuffer(java.nio.ByteBuffer)

Aggregations

BATBlock (org.apache.poi.poifs.storage.BATBlock)11 ByteBuffer (java.nio.ByteBuffer)7 ByteArrayInputStream (java.io.ByteArrayInputStream)2 ArrayList (java.util.ArrayList)2 HeaderBlockWriter (org.apache.poi.poifs.storage.HeaderBlockWriter)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 InputStream (java.io.InputStream)1 NPropertyTable (org.apache.poi.poifs.property.NPropertyTable)1 BlockAllocationTableReader (org.apache.poi.poifs.storage.BlockAllocationTableReader)1 BlockAllocationTableWriter (org.apache.poi.poifs.storage.BlockAllocationTableWriter)1 BlockWritable (org.apache.poi.poifs.storage.BlockWritable)1 HeaderBlock (org.apache.poi.poifs.storage.HeaderBlock)1 RawDataBlockList (org.apache.poi.poifs.storage.RawDataBlockList)1 SmallBlockTableWriter (org.apache.poi.poifs.storage.SmallBlockTableWriter)1