diff options
Diffstat (limited to 'src/java/org/apache/poi/poifs/filesystem/POIFSStream.java')
-rw-r--r-- | src/java/org/apache/poi/poifs/filesystem/POIFSStream.java | 406 |
1 files changed, 203 insertions, 203 deletions
diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java b/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java index 8d8f7c575d..d1b83afc04 100644 --- a/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java +++ b/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java @@ -32,155 +32,155 @@ import org.apache.poi.poifs.storage.HeaderBlock; /** * This handles reading and writing a stream within a - * {@link POIFSFileSystem}. It can supply an iterator - * to read blocks, and way to write out to existing and - * new blocks. + * {@link POIFSFileSystem}. It can supply an iterator + * to read blocks, and way to write out to existing and + * new blocks. * Most users will want a higher level version of this, - * which deals with properties to track which stream - * this is. + * which deals with properties to track which stream + * this is. * This only works on big block streams, it doesn't - * handle small block ones. + * handle small block ones. * This uses the new NIO code - * + * <p> * TODO Implement a streaming write method, and append */ -public class POIFSStream implements Iterable<ByteBuffer> -{ - private final BlockStore blockStore; - private int startBlock; - private OutputStream outStream; - - /** - * Constructor for an existing stream. It's up to you - * to know how to get the start block (eg from a - * {@link HeaderBlock} or a {@link Property}) - */ - public POIFSStream(BlockStore blockStore, int startBlock) { - this.blockStore = blockStore; - this.startBlock = startBlock; - } - - /** - * Constructor for a new stream. A start block won't - * be allocated until you begin writing to it. - */ - public POIFSStream(BlockStore blockStore) { - this.blockStore = blockStore; - this.startBlock = POIFSConstants.END_OF_CHAIN; - } - - /** - * What block does this stream start at? - * Will be {@link POIFSConstants#END_OF_CHAIN} for a - * new stream that hasn't been written to yet. - */ - public int getStartBlock() { - return startBlock; - } - - /** - * Returns an iterator that'll supply one {@link ByteBuffer} - * per block in the stream. - */ - public Iterator<ByteBuffer> iterator() { - return getBlockIterator(); - } - - Iterator<ByteBuffer> getBlockIterator() { - if(startBlock == POIFSConstants.END_OF_CHAIN) { - throw new IllegalStateException( - "Can't read from a new stream before it has been written to" - ); - } - return new StreamBlockByteBufferIterator(startBlock); - } - - Iterator<Integer> getBlockOffsetIterator() { - if(startBlock == POIFSConstants.END_OF_CHAIN) { - throw new IllegalStateException( - "Can't read from a new stream before it has been written to" - ); - } - return new StreamBlockOffsetIterator(startBlock); - } - - /** - * Updates the contents of the stream to the new - * set of bytes. - * Note - if this is property based, you'll still - * need to update the size in the property yourself - */ - void updateContents(byte[] contents) throws IOException { - OutputStream os = getOutputStream(); - os.write(contents); - os.close(); - } - - public OutputStream getOutputStream() throws IOException { - if (outStream == null) { - outStream = new StreamBlockByteBuffer(); - } - return outStream; - } - - // TODO Streaming write support - // TODO then convert fixed sized write to use streaming internally - // TODO Append write support (probably streaming) - - /** - * Frees all blocks in the stream - */ - public void free() throws IOException { - ChainLoopDetector loopDetector = blockStore.getChainLoopDetector(); - free(loopDetector); - } - private void free(ChainLoopDetector loopDetector) { - int nextBlock = startBlock; - while(nextBlock != POIFSConstants.END_OF_CHAIN) { - int thisBlock = nextBlock; - loopDetector.claim(thisBlock); - nextBlock = blockStore.getNextBlock(thisBlock); - blockStore.setNextBlock(thisBlock, POIFSConstants.UNUSED_BLOCK); - } - this.startBlock = POIFSConstants.END_OF_CHAIN; - } - - /** - * Class that handles a streaming read of one stream - */ - private class StreamBlockOffsetIterator implements Iterator<Integer> { - private final ChainLoopDetector loopDetector; - private int nextBlock; - - StreamBlockOffsetIterator(int firstBlock) { - this.nextBlock = firstBlock; - try { - this.loopDetector = blockStore.getChainLoopDetector(); - } catch(IOException e) { - throw new RuntimeException(e); - } - } - - public boolean hasNext() { - return nextBlock != POIFSConstants.END_OF_CHAIN; - } - - public Integer next() { - if (!hasNext()) { - throw new NoSuchElementException("Can't read past the end of the stream"); - } - - loopDetector.claim(nextBlock); - int currentBlock = nextBlock; - nextBlock = blockStore.getNextBlock(nextBlock); - return currentBlock; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - } +public class POIFSStream implements Iterable<ByteBuffer> { + private final BlockStore blockStore; + private int startBlock; + private OutputStream outStream; + + /** + * Constructor for an existing stream. It's up to you + * to know how to get the start block (eg from a + * {@link HeaderBlock} or a {@link Property}) + */ + public POIFSStream(BlockStore blockStore, int startBlock) { + this.blockStore = blockStore; + this.startBlock = startBlock; + } + + /** + * Constructor for a new stream. A start block won't + * be allocated until you begin writing to it. + */ + public POIFSStream(BlockStore blockStore) { + this.blockStore = blockStore; + this.startBlock = POIFSConstants.END_OF_CHAIN; + } + + /** + * What block does this stream start at? + * Will be {@link POIFSConstants#END_OF_CHAIN} for a + * new stream that hasn't been written to yet. + */ + public int getStartBlock() { + return startBlock; + } + + /** + * Returns an iterator that'll supply one {@link ByteBuffer} + * per block in the stream. + */ + public Iterator<ByteBuffer> iterator() { + return getBlockIterator(); + } + + Iterator<ByteBuffer> getBlockIterator() { + if (startBlock == POIFSConstants.END_OF_CHAIN) { + throw new IllegalStateException( + "Can't read from a new stream before it has been written to" + ); + } + return new StreamBlockByteBufferIterator(startBlock); + } + + Iterator<Integer> getBlockOffsetIterator() { + if (startBlock == POIFSConstants.END_OF_CHAIN) { + throw new IllegalStateException( + "Can't read from a new stream before it has been written to" + ); + } + return new StreamBlockOffsetIterator(startBlock); + } + + /** + * Updates the contents of the stream to the new + * set of bytes. + * Note - if this is property based, you'll still + * need to update the size in the property yourself + */ + void updateContents(byte[] contents) throws IOException { + OutputStream os = getOutputStream(); + os.write(contents); + os.close(); + } + + public OutputStream getOutputStream() throws IOException { + if (outStream == null) { + outStream = new StreamBlockByteBuffer(); + } + return outStream; + } + + // TODO Streaming write support + // TODO then convert fixed sized write to use streaming internally + // TODO Append write support (probably streaming) + + /** + * Frees all blocks in the stream + */ + public void free() throws IOException { + ChainLoopDetector loopDetector = blockStore.getChainLoopDetector(); + free(loopDetector); + } + + private void free(ChainLoopDetector loopDetector) { + int nextBlock = startBlock; + while (nextBlock != POIFSConstants.END_OF_CHAIN) { + int thisBlock = nextBlock; + loopDetector.claim(thisBlock); + nextBlock = blockStore.getNextBlock(thisBlock); + blockStore.setNextBlock(thisBlock, POIFSConstants.UNUSED_BLOCK); + } + this.startBlock = POIFSConstants.END_OF_CHAIN; + } + + /** + * Class that handles a streaming read of one stream + */ + private class StreamBlockOffsetIterator implements Iterator<Integer> { + private final ChainLoopDetector loopDetector; + private int nextBlock; + + StreamBlockOffsetIterator(int firstBlock) { + this.nextBlock = firstBlock; + try { + this.loopDetector = blockStore.getChainLoopDetector(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public boolean hasNext() { + return nextBlock != POIFSConstants.END_OF_CHAIN; + } + + public Integer next() { + if (!hasNext()) { + throw new NoSuchElementException("Can't read past the end of the stream"); + } + + loopDetector.claim(nextBlock); + int currentBlock = nextBlock; + nextBlock = blockStore.getNextBlock(nextBlock); + return currentBlock; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } /** * Class that handles a streaming read of one stream @@ -203,7 +203,7 @@ public class POIFSStream implements Iterable<ByteBuffer> try { return blockStore.getBlockAt(offsetIterator.next()); - } catch(IOException e) { + } catch (IOException e) { throw new RuntimeException(e); } } @@ -214,66 +214,66 @@ public class POIFSStream implements Iterable<ByteBuffer> } - protected class StreamBlockByteBuffer extends OutputStream { - byte[] oneByte = new byte[1]; - ByteBuffer buffer; - // Make sure we don't encounter a loop whilst overwriting - // the existing blocks - ChainLoopDetector loopDetector; - int prevBlock, nextBlock; - - StreamBlockByteBuffer() throws IOException { - loopDetector = blockStore.getChainLoopDetector(); - prevBlock = POIFSConstants.END_OF_CHAIN; - nextBlock = startBlock; - } - - void createBlockIfNeeded() throws IOException { - if (buffer != null && buffer.hasRemaining()) return; - - int thisBlock = nextBlock; - - // Allocate a block if needed, otherwise figure - // out what the next block will be - if(thisBlock == POIFSConstants.END_OF_CHAIN) { - thisBlock = blockStore.getFreeBlock(); - loopDetector.claim(thisBlock); - - // We're on the end of the chain - nextBlock = POIFSConstants.END_OF_CHAIN; - - // Mark the previous block as carrying on to us if needed - if(prevBlock != POIFSConstants.END_OF_CHAIN) { - blockStore.setNextBlock(prevBlock, thisBlock); - } - blockStore.setNextBlock(thisBlock, POIFSConstants.END_OF_CHAIN); - - // If we've just written the first block on a - // new stream, save the start block offset - if(startBlock == POIFSConstants.END_OF_CHAIN) { - startBlock = thisBlock; - } - } else { - loopDetector.claim(thisBlock); - nextBlock = blockStore.getNextBlock(thisBlock); - } - - if (buffer != null) { - blockStore.releaseBuffer(buffer); - } - buffer = blockStore.createBlockIfNeeded(thisBlock); - - // Update pointers - prevBlock = thisBlock; - } - - @Override - public void write(int b) throws IOException { - oneByte[0] = (byte)(b & 0xFF); + protected class StreamBlockByteBuffer extends OutputStream { + byte[] oneByte = new byte[1]; + ByteBuffer buffer; + // Make sure we don't encounter a loop whilst overwriting + // the existing blocks + ChainLoopDetector loopDetector; + int prevBlock, nextBlock; + + StreamBlockByteBuffer() throws IOException { + loopDetector = blockStore.getChainLoopDetector(); + prevBlock = POIFSConstants.END_OF_CHAIN; + nextBlock = startBlock; + } + + void createBlockIfNeeded() throws IOException { + if (buffer != null && buffer.hasRemaining()) return; + + int thisBlock = nextBlock; + + // Allocate a block if needed, otherwise figure + // out what the next block will be + if (thisBlock == POIFSConstants.END_OF_CHAIN) { + thisBlock = blockStore.getFreeBlock(); + loopDetector.claim(thisBlock); + + // We're on the end of the chain + nextBlock = POIFSConstants.END_OF_CHAIN; + + // Mark the previous block as carrying on to us if needed + if (prevBlock != POIFSConstants.END_OF_CHAIN) { + blockStore.setNextBlock(prevBlock, thisBlock); + } + blockStore.setNextBlock(thisBlock, POIFSConstants.END_OF_CHAIN); + + // If we've just written the first block on a + // new stream, save the start block offset + if (startBlock == POIFSConstants.END_OF_CHAIN) { + startBlock = thisBlock; + } + } else { + loopDetector.claim(thisBlock); + nextBlock = blockStore.getNextBlock(thisBlock); + } + + if (buffer != null) { + blockStore.releaseBuffer(buffer); + } + buffer = blockStore.createBlockIfNeeded(thisBlock); + + // Update pointers + prevBlock = thisBlock; + } + + @Override + public void write(int b) throws IOException { + oneByte[0] = (byte) (b & 0xFF); write(oneByte); - } + } - @Override + @Override public void write(byte[] b, int off, int len) throws IOException { if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { @@ -301,6 +301,6 @@ public class POIFSStream implements Iterable<ByteBuffer> blockStore.setNextBlock(prevBlock, POIFSConstants.END_OF_CHAIN); } } - } + } } |