diff options
Diffstat (limited to 'src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java')
-rw-r--r-- | src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java | 152 |
1 files changed, 95 insertions, 57 deletions
diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java index 5d8d1fa882..5d444b8cb9 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java @@ -20,6 +20,7 @@ package org.apache.poi.poifs.filesystem; import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Iterator; @@ -47,6 +48,7 @@ public class NPOIFSStream implements Iterable<ByteBuffer> { private BlockStore blockStore; private int startBlock; + private OutputStream outStream; /** * Constructor for an existing stream. It's up to you @@ -92,7 +94,7 @@ public class NPOIFSStream implements Iterable<ByteBuffer> } return new StreamBlockByteBufferIterator(startBlock); } - + /** * Updates the contents of the stream to the new * set of bytes. @@ -100,62 +102,16 @@ public class NPOIFSStream implements Iterable<ByteBuffer> * need to update the size in the property yourself */ public void updateContents(byte[] contents) throws IOException { - // How many blocks are we going to need? - int blockSize = blockStore.getBlockStoreBlockSize(); - int blocks = (int)Math.ceil( ((double)contents.length) / blockSize ); - - // Make sure we don't encounter a loop whilst overwriting - // the existing blocks - ChainLoopDetector loopDetector = blockStore.getChainLoopDetector(); - - // Start writing - int prevBlock = POIFSConstants.END_OF_CHAIN; - int nextBlock = startBlock; - for(int i=0; i<blocks; i++) { - 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(this.startBlock == POIFSConstants.END_OF_CHAIN) { - this.startBlock = thisBlock; - } - } else { - loopDetector.claim(thisBlock); - nextBlock = blockStore.getNextBlock(thisBlock); - } - - // Write it - ByteBuffer buffer = blockStore.createBlockIfNeeded(thisBlock); - int startAt = i*blockSize; - int endAt = Math.min(contents.length - startAt, blockSize); - buffer.put(contents, startAt, endAt); - - // Update pointers - prevBlock = thisBlock; - } - int lastBlock = prevBlock; - - // If we're overwriting, free any remaining blocks - NPOIFSStream toFree = new NPOIFSStream(blockStore, nextBlock); - toFree.free(loopDetector); - - // Mark the end of the stream - blockStore.setNextBlock(lastBlock, POIFSConstants.END_OF_CHAIN); + 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 @@ -222,5 +178,87 @@ public class NPOIFSStream implements Iterable<ByteBuffer> throw new UnsupportedOperationException(); } } + + 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; + + protected StreamBlockByteBuffer() throws IOException { + loopDetector = blockStore.getChainLoopDetector(); + prevBlock = POIFSConstants.END_OF_CHAIN; + nextBlock = startBlock; + } + + protected 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); + } + + buffer = blockStore.createBlockIfNeeded(thisBlock); + + // Update pointers + prevBlock = thisBlock; + } + + public void write(int b) throws IOException { + oneByte[0] = (byte)(b & 0xFF); + write(oneByte); + } + + 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)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + + do { + createBlockIfNeeded(); + int writeBytes = Math.min(buffer.remaining(), len); + buffer.put(b, off, writeBytes); + off += writeBytes; + len -= writeBytes; + } while (len > 0); + } + + public void close() throws IOException { + // If we're overwriting, free any remaining blocks + NPOIFSStream toFree = new NPOIFSStream(blockStore, nextBlock); + toFree.free(loopDetector); + + // Mark the end of the stream + blockStore.setNextBlock(prevBlock, POIFSConstants.END_OF_CHAIN); + } + } } |