From fb5d21b1bb5a9a9d3f0583b45544975d84ee9d43 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sat, 13 Apr 2019 08:08:36 +0000 Subject: [PATCH] adjust formatting git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1857452 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/poifs/filesystem/POIFSFileSystem.java | 810 +++++++++--------- 1 file changed, 392 insertions(+), 418 deletions(-) diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java index 36c7648377..afec8a06ba 100644 --- a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java +++ b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java @@ -61,8 +61,7 @@ import org.apache.poi.util.POILogger; */ public class POIFSFileSystem extends BlockStore - implements POIFSViewable, Closeable -{ + implements POIFSViewable, Closeable { //arbitrarily selected; may need to increase private static final int MAX_RECORD_LENGTH = 100_000; @@ -71,7 +70,7 @@ public class POIFSFileSystem extends BlockStore /** * Maximum number size (in blocks) of the allocation table as supported by * POI.

- * + *

* This constant has been chosen to help POI identify corrupted data in the * header block (rather than crash immediately with {@link OutOfMemoryError} * ). It's not clear if the compound document format actually specifies any @@ -83,48 +82,46 @@ public class POIFSFileSystem extends BlockStore private POIFSMiniStore _mini_store; private PropertyTable _property_table; - private List _xbat_blocks; - private List _bat_blocks; - private HeaderBlock _header; - private DirectoryNode _root; - + private List _xbat_blocks; + private List _bat_blocks; + private HeaderBlock _header; + private DirectoryNode _root; + private DataSource _data; - + /** * What big block size the file uses. Most files - * use 512 bytes, but a few use 4096 + * use 512 bytes, but a few use 4096 */ - private POIFSBigBlockSize bigBlockSize = - POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; + private POIFSBigBlockSize bigBlockSize = + POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; - private POIFSFileSystem(boolean newFS) - { - _header = new HeaderBlock(bigBlockSize); + private POIFSFileSystem(boolean newFS) { + _header = new HeaderBlock(bigBlockSize); _property_table = new PropertyTable(_header); - _mini_store = new POIFSMiniStore(this, _property_table.getRoot(), new ArrayList<>(), _header); - _xbat_blocks = new ArrayList<>(); - _bat_blocks = new ArrayList<>(); - _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(IOUtils.safelyAllocate( - bigBlockSize.getBigBlockSize()*3, MAX_RECORD_LENGTH)); + _mini_store = new POIFSMiniStore(this, _property_table.getRoot(), new ArrayList<>(), _header); + _xbat_blocks = new ArrayList<>(); + _bat_blocks = new ArrayList<>(); + _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(IOUtils.safelyAllocate( + bigBlockSize.getBigBlockSize() * 3, MAX_RECORD_LENGTH)); } } - + /** * Constructor, intended for writing */ - public POIFSFileSystem() - { - this(true); - + public POIFSFileSystem() { + this(true); + // Reserve block 0 for the start of the Properties Table // Create a single empty BAT, at pop that at offset 1 _header.setBATCount(1); - _header.setBATArray(new int[] { 1 }); + _header.setBATArray(new int[]{1}); BATBlock bb = BATBlock.createEmptyBATBlock(bigBlockSize, false); bb.setOurBlockIndex(1); _bat_blocks.add(bb); @@ -137,121 +134,112 @@ public class POIFSFileSystem extends BlockStore /** *

Creates a POIFSFileSystem from a File. This uses less memory than - * creating from an InputStream. The File will be opened read-only

- * - *

Note that with this constructor, you will need to call {@link #close()} - * when you're done to have the underlying file closed, as the file is - * kept open during normal operation to read the data out.

- * - * @param file the File from which to read the data + * creating from an InputStream. The File will be opened read-only

* - * @exception IOException on errors reading, or on invalid data + *

Note that with this constructor, you will need to call {@link #close()} + * when you're done to have the underlying file closed, as the file is + * kept open during normal operation to read the data out.

+ * + * @param file the File from which to read the data + * @throws IOException on errors reading, or on invalid data */ public POIFSFileSystem(File file) - throws IOException - { - this(file, true); + throws IOException { + this(file, true); } - + /** *

Creates a POIFSFileSystem from a File. This uses less memory than - * creating from an InputStream.

- * - *

Note that with this constructor, you will need to call {@link #close()} - * when you're done to have the underlying file closed, as the file is - * kept open during normal operation to read the data out.

- * - * @param file the File from which to read or read/write the data - * @param readOnly whether the POIFileSystem will only be used in read-only mode + * creating from an InputStream.

* - * @exception IOException on errors reading, or on invalid data + *

Note that with this constructor, you will need to call {@link #close()} + * when you're done to have the underlying file closed, as the file is + * kept open during normal operation to read the data out.

+ * + * @param file the File from which to read or read/write the data + * @param readOnly whether the POIFileSystem will only be used in read-only mode + * @throws IOException on errors reading, or on invalid data */ public POIFSFileSystem(File file, boolean readOnly) - throws IOException - { - this(null, file, readOnly, true); + throws IOException { + this(null, file, readOnly, true); } - + /** - *

Creates a POIFSFileSystem from an open FileChannel. This uses - * less memory than creating from an InputStream. The stream will - * be used in read-only mode.

- * - *

Note that with this constructor, you will need to call {@link #close()} - * when you're done to have the underlying Channel closed, as the channel is - * kept open during normal operation to read the data out.

- * - * @param channel the FileChannel from which to read the data + *

Creates a POIFSFileSystem from an open FileChannel. This uses + * less memory than creating from an InputStream. The stream will + * be used in read-only mode.

* - * @exception IOException on errors reading, or on invalid data + *

Note that with this constructor, you will need to call {@link #close()} + * when you're done to have the underlying Channel closed, as the channel is + * kept open during normal operation to read the data out.

+ * + * @param channel the FileChannel from which to read the data + * @throws IOException on errors reading, or on invalid data */ public POIFSFileSystem(FileChannel channel) - throws IOException - { - this(channel, true); + throws IOException { + this(channel, true); } - + /** - *

Creates a POIFSFileSystem from an open FileChannel. This uses - * less memory than creating from an InputStream.

- * - *

Note that with this constructor, you will need to call {@link #close()} - * when you're done to have the underlying Channel closed, as the channel is - * kept open during normal operation to read the data out.

- * - * @param channel the FileChannel from which to read or read/write the data - * @param readOnly whether the POIFileSystem will only be used in read-only mode + *

Creates a POIFSFileSystem from an open FileChannel. This uses + * less memory than creating from an InputStream.

* - * @exception IOException on errors reading, or on invalid data + *

Note that with this constructor, you will need to call {@link #close()} + * when you're done to have the underlying Channel closed, as the channel is + * kept open during normal operation to read the data out.

+ * + * @param channel the FileChannel from which to read or read/write the data + * @param readOnly whether the POIFileSystem will only be used in read-only mode + * @throws IOException on errors reading, or on invalid data */ public POIFSFileSystem(FileChannel channel, boolean readOnly) - throws IOException - { - this(channel, null, readOnly, false); + throws IOException { + this(channel, null, readOnly, false); } - - private POIFSFileSystem(FileChannel channel, File srcFile, boolean readOnly, boolean closeChannelOnError) - throws IOException - { - this(false); - try { - // Initialize the datasource - if (srcFile != null) { - if (srcFile.length() == 0) - throw new EmptyFileException(); - - FileBackedDataSource d = new FileBackedDataSource(srcFile, readOnly); - channel = d.getChannel(); - _data = d; - } else { - _data = new FileBackedDataSource(channel, readOnly); - } - - // Get the header - ByteBuffer headerBuffer = ByteBuffer.allocate(POIFSConstants.SMALLER_BIG_BLOCK_SIZE); - IOUtils.readFully(channel, headerBuffer); - - // Have the header processed - _header = new HeaderBlock(headerBuffer); - - // Now process the various entries - readCoreContents(); - } catch(IOException | RuntimeException e) { - // Comes from Iterators etc. - // TODO Decide if we can handle these better whilst - // still sticking to the iterator contract - if (closeChannelOnError && channel != null) { - channel.close(); - } - throw e; - } + private POIFSFileSystem(FileChannel channel, File srcFile, boolean readOnly, boolean closeChannelOnError) + throws IOException { + this(false); + + try { + // Initialize the datasource + if (srcFile != null) { + if (srcFile.length() == 0) + throw new EmptyFileException(); + + FileBackedDataSource d = new FileBackedDataSource(srcFile, readOnly); + channel = d.getChannel(); + _data = d; + } else { + _data = new FileBackedDataSource(channel, readOnly); + } + + // Get the header + ByteBuffer headerBuffer = ByteBuffer.allocate(POIFSConstants.SMALLER_BIG_BLOCK_SIZE); + IOUtils.readFully(channel, headerBuffer); + + // Have the header processed + _header = new HeaderBlock(headerBuffer); + + // Now process the various entries + readCoreContents(); + } catch (IOException | RuntimeException e) { + // Comes from Iterators etc. + // TODO Decide if we can handle these better whilst + // still sticking to the iterator contract + if (closeChannelOnError && channel != null) { + channel.close(); + } + throw e; + } } - + /** * Create a POIFSFileSystem from an InputStream. Normally the stream is read until * EOF. The stream is always closed.

- * + *

* Some streams are usable after reaching EOF (typically those that return true * for markSupported()). In the unlikely case that the caller has such a stream * and needs to use it after this constructor completes, a work around is to wrap the @@ -273,13 +261,11 @@ public class POIFSFileSystem extends BlockStore * * * @param stream the InputStream from which to read the data - * - * @exception IOException on errors reading, or on invalid data + * @throws IOException on errors reading, or on invalid data */ public POIFSFileSystem(InputStream stream) - throws IOException - { + throws IOException { this(false); boolean success = false; @@ -320,19 +306,20 @@ public class POIFSFileSystem extends BlockStore // As per the constructor contract, always close the stream closeInputStream(stream, success); } - + // Now process the various entries readCoreContents(); } + /** - * @param stream the stream to be closed + * @param stream the stream to be closed * @param success false if an exception is currently being thrown in the calling method */ private void closeInputStream(InputStream stream, boolean success) { try { stream.close(); } catch (IOException e) { - if(success) { + if (success) { throw new RuntimeException(e); } // else not success? Try block did not complete normally @@ -343,268 +330,269 @@ public class POIFSFileSystem extends BlockStore /** * Read and process the PropertiesTable and the - * FAT / XFAT blocks, so that we're ready to - * work with the file + * 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 sbats = new ArrayList<>(); - _mini_store = new POIFSMiniStore(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); - } + // 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 PropertyTable(_header, this); + + // Finally read the Small Stream FAT (SBAT) blocks + BATBlock sfat; + List sbats = new ArrayList<>(); + _mini_store = new POIFSMiniStore(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); + } } + 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); + loopDetector.claim(batAt); + ByteBuffer fatData = getBlockAt(batAt); + BATBlock bat = BATBlock.createBATBlock(bigBlockSize, fatData); + bat.setOurBlockIndex(batAt); + _bat_blocks.add(bat); } + 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; + // 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; } - + /** * 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 blockWanted = offset + 1L; - long startAt = blockWanted * bigBlockSize.getBigBlockSize(); - try { - return _data.read(bigBlockSize.getBigBlockSize(), startAt); - } catch (IndexOutOfBoundsException e) { - IndexOutOfBoundsException wrapped = new IndexOutOfBoundsException("Block " + offset + " not found"); - wrapped.initCause(e); - throw wrapped; - } + // The header block doesn't count, so add one + long blockWanted = offset + 1L; + long startAt = blockWanted * bigBlockSize.getBigBlockSize(); + try { + return _data.read(bigBlockSize.getBigBlockSize(), startAt); + } catch (IndexOutOfBoundsException e) { + IndexOutOfBoundsException wrapped = new IndexOutOfBoundsException("Block " + offset + " not found"); + wrapped.initCause(e); + throw wrapped; + } } - + /** - * Load the block at the given offset, - * extending the file if needed + * 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+1L) * bigBlockSize.getBigBlockSize(); - // Allocate and write - ByteBuffer buffer = ByteBuffer.allocate(getBigBlockSize()); - _data.write(buffer, startAt); - // Retrieve the properly backed block - return getBlockAt(offset); - } + try { + return getBlockAt(offset); + } catch (IndexOutOfBoundsException e) { + // The header block doesn't count, so add one + long startAt = (offset + 1L) * bigBlockSize.getBigBlockSize(); + // Allocate and write + ByteBuffer buffer = ByteBuffer.allocate(getBigBlockSize()); + _data.write(buffer, startAt); + // Retrieve the properly backed block + return getBlockAt(offset); + } } - + /** * Returns the BATBlock that handles the specified offset, - * and the relative index within it + * and the relative index within it */ @Override protected BATBlockAndIndex getBATBlockAndIndex(final int offset) { - return BATBlock.getBATBlockAndIndex( - offset, _header, _bat_blocks - ); + return BATBlock.getBATBlockAndIndex( + offset, _header, _bat_blocks + ); } - + /** * Works out what block follows the specified one. */ @Override protected int getNextBlock(final int offset) { - BATBlockAndIndex bai = getBATBlockAndIndex(offset); - return bai.getBlock().getValueAt( bai.getIndex() ); + BATBlockAndIndex bai = getBATBlockAndIndex(offset); + return bai.getBlock().getValueAt(bai.getIndex()); } - + /** * Changes the record of what block follows the specified one. */ @Override protected void setNextBlock(final int offset, final int nextBlock) { - BATBlockAndIndex bai = getBATBlockAndIndex(offset); - bai.getBlock().setValueAt( - bai.getIndex(), nextBlock - ); + BATBlockAndIndex bai = getBATBlockAndIndex(offset); + bai.getBlock().setValueAt( + bai.getIndex(), nextBlock + ); } - + /** * 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. + * 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= 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= 109) { + // Needs to come from an XBAT + BATBlock xbat = null; + for (BATBlock x : _xbat_blocks) { + if (x.hasFreeSectors()) { + xbat = x; 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; + } + } + 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; } - + protected long size() throws IOException { return _data.size(); } - + @Override protected ChainLoopDetector getChainLoopDetector() throws IOException { - return new ChainLoopDetector(_data.size()); + return new ChainLoopDetector(_data.size()); } - /** + /** * For unit testing only! Returns the underlying - * properties table + * properties table */ PropertyTable _get_property_table() { - return _property_table; - } - - /** - * Returns the MiniStore, which performs a similar low - * level function to this, except for the small blocks. - */ - POIFSMiniStore getMiniStore() { - return _mini_store; + return _property_table; } /** - * add a new POIFSDocument to the FileSytem + * Returns the MiniStore, which performs a similar low + * level function to this, except for the small blocks. + */ + POIFSMiniStore getMiniStore() { + return _mini_store; + } + + /** + * add a new POIFSDocument to the FileSytem * * @param document the POIFSDocument being added */ - void addDocument(final POIFSDocument document) - { + void addDocument(final POIFSDocument document) { _property_table.addProperty(document.getDocumentProperty()); } @@ -613,27 +601,23 @@ public class POIFSFileSystem extends BlockStore * * @param directory the DirectoryProperty being added */ - void addDirectory(final DirectoryProperty directory) - { + void addDirectory(final DirectoryProperty directory) { _property_table.addProperty(directory); } - /** + /** * Create a new document to be added to the root directory * * @param stream the InputStream from which the document's data * will be obtained - * @param name the name of the new POIFSDocument - * + * @param name the name of the new POIFSDocument * @return the new DocumentEntry - * - * @exception IOException on error creating the new POIFSDocument + * @throws IOException on error creating the new POIFSDocument */ public DocumentEntry createDocument(final InputStream stream, final String name) - throws IOException - { + throws IOException { return getRoot().createDocument(name, stream); } @@ -641,16 +625,14 @@ public class POIFSFileSystem extends BlockStore * create a new DocumentEntry in the root entry; the data will be * provided later * - * @param name the name of the new DocumentEntry - * @param size the size of the new DocumentEntry + * @param name the name of the new DocumentEntry + * @param size the size of the new DocumentEntry * @param writer the writer of the new DocumentEntry - * * @return the new DocumentEntry - * - * @exception IOException if the writer exceeds the given size + * @throws IOException if the writer exceeds the given size */ public DocumentEntry createDocument(final String name, final int size, final POIFSWriterListener writer) - throws IOException { + throws IOException { return getRoot().createDocument(name, size, writer); } @@ -658,67 +640,62 @@ public class POIFSFileSystem extends BlockStore * create a new DirectoryEntry in the root directory * * @param name the name of the new DirectoryEntry - * * @return the new DirectoryEntry - * - * @exception IOException on name duplication + * @throws IOException on name duplication */ public DirectoryEntry createDirectory(final String name) - throws IOException - { + throws IOException { return getRoot().createDirectory(name); } - + /** * Set the contents of a document in the root directory, - * creating if needed, otherwise updating + * creating if needed, otherwise updating * * @param stream the InputStream from which the document's data * will be obtained - * @param name the name of the new or existing POIFSDocument - * + * @param name the name of the new or existing POIFSDocument * @return the new or updated DocumentEntry - * - * @exception IOException on error populating the POIFSDocument + * @throws IOException on error populating the POIFSDocument */ @SuppressWarnings("UnusedReturnValue") public DocumentEntry createOrUpdateDocument(final InputStream stream, final String name) - throws IOException { + throws IOException { return getRoot().createOrUpdateDocument(name, stream); } - + /** * Does the filesystem support an in-place write via - * {@link #writeFilesystem()} ? If false, only writing out to - * a brand new file via {@link #writeFilesystem(OutputStream)} - * is supported. + * {@link #writeFilesystem()} ? If false, only writing out to + * a brand new file via {@link #writeFilesystem(OutputStream)} + * is supported. */ public boolean isInPlaceWriteable() { return (_data instanceof FileBackedDataSource) && ((FileBackedDataSource) _data).isWriteable(); } - + /** * Write the filesystem out to the open file. Will thrown an - * {@link IllegalArgumentException} if opened from an - * {@link InputStream}. - * - * @exception IOException thrown on errors writing to the stream + * {@link IllegalArgumentException} if opened from an + * {@link InputStream}. + * + * @throws IOException thrown on errors writing to the stream */ public void writeFilesystem() throws IOException { - if (!(_data instanceof FileBackedDataSource)) { - throw new IllegalArgumentException( - "POIFS opened from an inputstream, so writeFilesystem() may " + - "not be called. Use writeFilesystem(OutputStream) instead" - ); - } - if (! ((FileBackedDataSource)_data).isWriteable()) { - throw new IllegalArgumentException( - "POIFS opened in read only mode, so writeFilesystem() may " + - "not be called. Open the FileSystem in read-write mode first" - ); - } - syncWithDataSource(); + if (!(_data instanceof FileBackedDataSource)) { + throw new IllegalArgumentException( + "POIFS opened from an inputstream, so writeFilesystem() may " + + "not be called. Use writeFilesystem(OutputStream) instead" + ); + } + if (!((FileBackedDataSource) _data).isWriteable()) { + throw new IllegalArgumentException( + "POIFS opened in read only mode, so writeFilesystem() may " + + "not be called. Open the FileSystem in read-write mode first" + ); + } + syncWithDataSource(); } /** @@ -726,32 +703,31 @@ public class POIFSFileSystem extends BlockStore * * @param stream the OutputStream to which the filesystem will be * written - * - * @exception IOException thrown on errors writing to the stream + * @throws IOException thrown on errors writing to the stream */ public void writeFilesystem(final OutputStream stream) throws IOException { - // Have the datasource updated - syncWithDataSource(); - - // Now copy the contents to the stream - _data.copyTo(stream); + // Have the datasource updated + syncWithDataSource(); + + // Now copy the contents to the stream + _data.copyTo(stream); } - + /** * Has our in-memory objects write their state - * to their backing blocks + * 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 POIFSStream propStream = new POIFSStream(this, _header.getPropertyStart()); _property_table.preWrite(); _property_table.write(propStream); // _header.setPropertyStart has been updated on write ... - + // HeaderBlock ByteArrayOutputStream baos = new ByteArrayOutputStream( _header.getBigBlockSize().getBigBlockSize() @@ -759,26 +735,26 @@ public class POIFSFileSystem extends BlockStore _header.writeData(baos); getBlockAt(-1).put(baos.toByteArray()); - - // BATs - for(BATBlock bat : _bat_blocks) { - ByteBuffer block = getBlockAt(bat.getOurBlockIndex()); - bat.writeData(block); - } - // XBats - for(BATBlock bat : _xbat_blocks) { - ByteBuffer block = getBlockAt(bat.getOurBlockIndex()); - bat.writeData(block); + + // BATs + for (BATBlock bat : _bat_blocks) { + ByteBuffer block = getBlockAt(bat.getOurBlockIndex()); + bat.writeData(block); + } + // XBats + for (BATBlock bat : _xbat_blocks) { + ByteBuffer block = getBlockAt(bat.getOurBlockIndex()); + bat.writeData(block); } } - + /** * Closes the FileSystem, freeing any underlying files, streams - * and buffers. After this, you will be unable to read or - * write from the FileSystem. + * and buffers. After this, you will be unable to read or + * write from the FileSystem. */ public void close() throws IOException { - _data.close(); + _data.close(); } /** @@ -790,7 +766,7 @@ public class POIFSFileSystem extends BlockStore public static void main(String[] args) throws IOException { if (args.length != 2) { System.err.println( - "two arguments required: input filename and output filename"); + "two arguments required: input filename and output filename"); System.exit(1); } @@ -810,7 +786,7 @@ public class POIFSFileSystem extends BlockStore */ public DirectoryNode getRoot() { if (_root == null) { - _root = new DirectoryNode(_property_table.getRoot(), this, null); + _root = new DirectoryNode(_property_table.getRoot(), this, null); } return _root; } @@ -819,15 +795,13 @@ public class POIFSFileSystem extends BlockStore * open a document in the root entry's list of entries * * @param documentName the name of the document to be opened - * * @return a newly opened DocumentInputStream - * - * @exception IOException if the document does not exist or the - * name is that of a DirectoryEntry + * @throws IOException if the document does not exist or the + * name is that of a DirectoryEntry */ public DocumentInputStream createDocumentInputStream( final String documentName) throws IOException { - return getRoot().createDocumentInputStream(documentName); + return getRoot().createDocumentInputStream(documentName); } /** @@ -838,14 +812,14 @@ public class POIFSFileSystem extends BlockStore void remove(EntryNode entry) throws IOException { // If it's a document, free the blocks if (entry instanceof DocumentEntry) { - POIFSDocument doc = new POIFSDocument((DocumentProperty)entry.getProperty(), this); + POIFSDocument doc = new POIFSDocument((DocumentProperty) entry.getProperty(), this); doc.free(); } - + // Now zap it from the properties list _property_table.removeProperty(entry.getProperty()); } - + /* ********** START begin implementation of POIFSViewable ********** */ /** @@ -854,12 +828,12 @@ public class POIFSFileSystem extends BlockStore * * @return an array of Object; may not be null, but may be empty */ - public Object [] getViewableArray() { + public Object[] getViewableArray() { if (preferArray()) { return getRoot().getViewableArray(); } - return new Object[ 0 ]; + return new Object[0]; } /** @@ -883,7 +857,7 @@ public class POIFSFileSystem extends BlockStore * getViewableIterator * * @return true if a viewer should call getViewableArray, false if - * a viewer should call getViewableIterator + * a viewer should call getViewableIterator */ public boolean preferArray() { @@ -907,7 +881,7 @@ public class POIFSFileSystem extends BlockStore * @return The Big Block size, normally 512 bytes, sometimes 4096 bytes */ public int getBigBlockSize() { - return bigBlockSize.getBigBlockSize(); + return bigBlockSize.getBigBlockSize(); } /** @@ -915,13 +889,13 @@ public class POIFSFileSystem extends BlockStore */ @SuppressWarnings("WeakerAccess") public POIFSBigBlockSize getBigBlockSizeDetails() { - return bigBlockSize; + return bigBlockSize; } /** * Creates a new {@link POIFSFileSystem} in a new {@link File}. * Use {@link #POIFSFileSystem(File)} to open an existing File, - * this should only be used to create a new empty filesystem. + * this should only be used to create a new empty filesystem. * * @param file The file to create and open * @return The created and opened {@link POIFSFileSystem} @@ -939,7 +913,7 @@ public class POIFSFileSystem extends BlockStore @Override protected int getBlockStoreBlockSize() { - return getBigBlockSize(); + return getBigBlockSize(); } @Internal