/** * 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(); i++) { loopDetector.claim(nextAt); ByteBuffer fatData = getBlockAt(nextAt); sfat = BATBlock.createBATBlock(bigBlockSize, fatData); sfat.setOurBlockIndex(nextAt); sbats.add(sfat); nextAt = getNextBlock(nextAt); } }
/** * 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 { // First up, do we have any spare ones? int offset = 0; for (int i = 0; i < _bat_blocks.size(); i++) { int numSectors = bigBlockSize.getBATEntriesPerBlock(); // Check this one BATBlock bat = _bat_blocks.get(i); 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); xbat.setValueAt(0, offset); 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()); } // Allocate us in the XBAT for (int i = 0; i < bigBlockSize.getXBATEntriesPerBlock(); i++) { if (xbat.getValueAt(i) == POIFSConstants.UNUSED_BLOCK) { xbat.setValueAt(i, offset); } } } 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; }