示例#1
0
    /** @return number of big blocks making up this document */
    int countBlocks() {

      if (isValid()) {
        if (_writer == null) {
          return bigBlocks.length;
        }
        return (_size + _bigBlockSize.getBigBlockSize() - 1) / _bigBlockSize.getBigBlockSize();
      }
      return 0;
    }
示例#2
0
  /**
   * 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);
    }
  }
示例#3
0
 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());
   int writeTo = (1 + offset) * bigBlockSize.getBigBlockSize(); // Header isn't in BATs
   _data.write(buffer, writeTo);
   // All done
   return newBAT;
 }
示例#4
0
 /** Load the block at the given offset, extending the file if needed */
 @Override
 protected ByteBuffer createBlockIfNeeded(final int offset) throws IOException {
   try {
     return getBlockAt(offset);
   } catch (IndexOutOfBoundsException e) {
     // The header block doesn't count, so add one
     long startAt = (offset + 1) * bigBlockSize.getBigBlockSize();
     // Allocate and write
     ByteBuffer buffer = ByteBuffer.allocate(getBigBlockSize());
     _data.write(buffer, startAt);
     // Retrieve the properly backed block
     return getBlockAt(offset);
   }
 }
示例#5
0
    /**
     * write the blocks to a stream
     *
     * @param stream the stream to which the data is to be written
     */
    void writeBlocks(OutputStream stream) throws IOException {
      if (isValid()) {
        if (_writer != null) {
          DocumentOutputStream dstream = new DocumentOutputStream(stream, _size);

          _writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, _path, _name, _size));
          dstream.writeFiller(
              countBlocks() * _bigBlockSize.getBigBlockSize(), DocumentBlock.getFillByte());
        } else {
          for (int k = 0; k < bigBlocks.length; k++) {
            bigBlocks[k].writeBlocks(stream);
          }
        }
      }
    }
示例#6
0
  private NPOIFSFileSystem(boolean newFS) {
    _header = new HeaderBlock(bigBlockSize);
    _property_table = new NPropertyTable(_header);
    _mini_store =
        new NPOIFSMiniStore(this, _property_table.getRoot(), new ArrayList<BATBlock>(), _header);
    _xbat_blocks = new ArrayList<BATBlock>();
    _bat_blocks = new ArrayList<BATBlock>();
    _root = null;

    if (newFS) {
      // Data needs to initially hold just the header block,
      //  a single bat block, and an empty properties section
      _data = new ByteArrayBackedDataSource(new byte[bigBlockSize.getBigBlockSize() * 3]);
    }
  }
示例#7
0
 /** @return The Big Block size, normally 512 bytes, sometimes 4096 bytes */
 public int getBigBlockSize() {
   return bigBlockSize.getBigBlockSize();
 }
示例#8
0
  /**
   * 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;
  }
示例#9
0
 /** Load the block at the given offset. */
 @Override
 protected ByteBuffer getBlockAt(final int offset) throws IOException {
   // The header block doesn't count, so add one
   long startAt = (offset + 1) * bigBlockSize.getBigBlockSize();
   return _data.read(bigBlockSize.getBigBlockSize(), startAt);
 }