You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ni...@apache.org on 2010/12/30 03:35:11 UTC
svn commit: r1053791 [4/18] - in /poi/branches/NIO_32_BRANCH: ./
src/contrib/src/org/apache/poi/contrib/poibrowser/ src/java/org/apache/poi/
src/java/org/apache/poi/hpsf/ src/java/org/apache/poi/hpsf/extractor/
src/java/org/apache/poi/hssf/record/ src/...
Added: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java?rev=1053791&view=auto
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java (added)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/NPOIFSStream.java Thu Dec 30 02:35:06 2010
@@ -0,0 +1,224 @@
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.poifs.filesystem;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.poifs.filesystem.BlockStore.ChainLoopDetector;
+import org.apache.poi.poifs.property.Property;
+import org.apache.poi.poifs.storage.HeaderBlock;
+
+/**
+ * This handles reading and writing a stream within a
+ * {@link NPOIFSFileSystem}. 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.
+ * This only works on big block streams, it doesn't
+ * handle small block ones.
+ * This uses the new NIO code
+ *
+ * TODO Implement a streaming write method, and append
+ */
+
+public class NPOIFSStream implements Iterable<ByteBuffer>
+{
+ private BlockStore blockStore;
+ private int startBlock;
+
+ /**
+ * 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 NPOIFSStream(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 NPOIFSStream(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();
+ }
+
+ public 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);
+ }
+
+ /**
+ * 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
+ */
+ public void updateContents(byte[] contents) throws IOException {
+ // How many blocks are we going to need?
+ int blockSize = blockStore.getBlockStoreBlockSize();
+ int blocks = (int)Math.ceil(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);
+ buffer.put(contents, i*blockSize, blockSize);
+
+ // 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);
+ }
+
+ // 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
+ */
+ protected class StreamBlockByteBufferIterator implements Iterator<ByteBuffer> {
+ private ChainLoopDetector loopDetector;
+ private int nextBlock;
+
+ protected StreamBlockByteBufferIterator(int firstBlock) {
+ this.nextBlock = firstBlock;
+ try {
+ this.loopDetector = blockStore.getChainLoopDetector();
+ } catch(IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean hasNext() {
+ if(nextBlock == POIFSConstants.END_OF_CHAIN) {
+ return false;
+ }
+ return true;
+ }
+
+ public ByteBuffer next() {
+ if(nextBlock == POIFSConstants.END_OF_CHAIN) {
+ throw new IndexOutOfBoundsException("Can't read past the end of the stream");
+ }
+
+ try {
+ loopDetector.claim(nextBlock);
+ ByteBuffer data = blockStore.getBlockAt(nextBlock);
+ nextBlock = blockStore.getNextBlock(nextBlock);
+ return data;
+ } catch(IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
+
Added: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java?rev=1053791&view=auto
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java (added)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/ODocumentInputStream.java Thu Dec 30 02:35:06 2010
@@ -0,0 +1,321 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.filesystem;
+
+import java.io.IOException;
+
+import org.apache.poi.poifs.storage.DataInputBlock;
+
+/**
+ * This class provides methods to read a DocumentEntry managed by a
+ * {@link POIFSFileSystem} instance.
+ *
+ * @author Marc Johnson (mjohnson at apache dot org)
+ */
+public final class ODocumentInputStream extends DocumentInputStream {
+ /** current offset into the Document */
+ private int _current_offset;
+
+ /** current marked offset into the Document (used by mark and reset) */
+ private int _marked_offset;
+
+ /** the Document's size */
+ private int _document_size;
+
+ /** have we been closed? */
+ private boolean _closed;
+
+ /** the actual Document */
+ private POIFSDocument _document;
+
+ /** the data block containing the current stream pointer */
+ private DataInputBlock _currentBlock;
+
+ /**
+ * Create an InputStream from the specified DocumentEntry
+ *
+ * @param document the DocumentEntry to be read
+ *
+ * @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
+ * been deleted?)
+ */
+ public ODocumentInputStream(DocumentEntry document) throws IOException {
+ if (!(document instanceof DocumentNode)) {
+ throw new IOException("Cannot open internal document storage");
+ }
+ DocumentNode documentNode = (DocumentNode)document;
+ if(documentNode.getDocument() == null) {
+ throw new IOException("Cannot open internal document storage");
+ }
+
+ _current_offset = 0;
+ _marked_offset = 0;
+ _document_size = document.getSize();
+ _closed = false;
+ _document = documentNode.getDocument();
+ _currentBlock = getDataInputBlock(0);
+ }
+
+ /**
+ * Create an InputStream from the specified Document
+ *
+ * @param document the Document to be read
+ */
+ public ODocumentInputStream(POIFSDocument document) {
+ _current_offset = 0;
+ _marked_offset = 0;
+ _document_size = document.getSize();
+ _closed = false;
+ _document = document;
+ _currentBlock = getDataInputBlock(0);
+ }
+
+ @Override
+ public int available() {
+ if (_closed) {
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
+ }
+ return _document_size - _current_offset;
+ }
+
+ @Override
+ public void close() {
+ _closed = true;
+ }
+
+ @Override
+ public void mark(int ignoredReadlimit) {
+ _marked_offset = _current_offset;
+ }
+
+ private DataInputBlock getDataInputBlock(int offset) {
+ return _document.getDataInputBlock(offset);
+ }
+
+ @Override
+ public int read() throws IOException {
+ dieIfClosed();
+ if (atEOD()) {
+ return EOF;
+ }
+ int result = _currentBlock.readUByte();
+ _current_offset++;
+ if (_currentBlock.available() < 1) {
+ _currentBlock = getDataInputBlock(_current_offset);
+ }
+ return result;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ dieIfClosed();
+ if (b == null) {
+ throw new IllegalArgumentException("buffer must not be null");
+ }
+ if (off < 0 || len < 0 || b.length < off + len) {
+ throw new IndexOutOfBoundsException("can't read past buffer boundaries");
+ }
+ if (len == 0) {
+ return 0;
+ }
+ if (atEOD()) {
+ return EOF;
+ }
+ int limit = Math.min(available(), len);
+ readFully(b, off, limit);
+ return limit;
+ }
+
+ /**
+ * Repositions this stream to the position at the time the mark() method was
+ * last called on this input stream. If mark() has not been called this
+ * method repositions the stream to its beginning.
+ */
+ @Override
+ public void reset() {
+ _current_offset = _marked_offset;
+ _currentBlock = getDataInputBlock(_current_offset);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ dieIfClosed();
+ if (n < 0) {
+ return 0;
+ }
+ int new_offset = _current_offset + (int) n;
+
+ if (new_offset < _current_offset) {
+
+ // wrap around in converting a VERY large long to an int
+ new_offset = _document_size;
+ } else if (new_offset > _document_size) {
+ new_offset = _document_size;
+ }
+ long rval = new_offset - _current_offset;
+
+ _current_offset = new_offset;
+ _currentBlock = getDataInputBlock(_current_offset);
+ return rval;
+ }
+
+ private void dieIfClosed() throws IOException {
+ if (_closed) {
+ throw new IOException("cannot perform requested operation on a closed stream");
+ }
+ }
+
+ private boolean atEOD() {
+ return _current_offset == _document_size;
+ }
+
+ private void checkAvaliable(int requestedSize) {
+ if (_closed) {
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
+ }
+ if (requestedSize > _document_size - _current_offset) {
+ throw new RuntimeException("Buffer underrun - requested " + requestedSize
+ + " bytes but " + (_document_size - _current_offset) + " was available");
+ }
+ }
+
+ @Override
+ public byte readByte() {
+ return (byte) readUByte();
+ }
+
+ @Override
+ public double readDouble() {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ @Override
+ public short readShort() {
+ return (short) readUShort();
+ }
+
+ @Override
+ public void readFully(byte[] buf, int off, int len) {
+ checkAvaliable(len);
+ int blockAvailable = _currentBlock.available();
+ if (blockAvailable > len) {
+ _currentBlock.readFully(buf, off, len);
+ _current_offset += len;
+ return;
+ }
+ // else read big amount in chunks
+ int remaining = len;
+ int writePos = off;
+ while (remaining > 0) {
+ boolean blockIsExpiring = remaining >= blockAvailable;
+ int reqSize;
+ if (blockIsExpiring) {
+ reqSize = blockAvailable;
+ } else {
+ reqSize = remaining;
+ }
+ _currentBlock.readFully(buf, writePos, reqSize);
+ remaining -= reqSize;
+ writePos += reqSize;
+ _current_offset += reqSize;
+ if (blockIsExpiring) {
+ if (_current_offset == _document_size) {
+ if (remaining > 0) {
+ throw new IllegalStateException(
+ "reached end of document stream unexpectedly");
+ }
+ _currentBlock = null;
+ break;
+ }
+ _currentBlock = getDataInputBlock(_current_offset);
+ blockAvailable = _currentBlock.available();
+ }
+ }
+ }
+
+ @Override
+ public long readLong() {
+ checkAvaliable(SIZE_LONG);
+ int blockAvailable = _currentBlock.available();
+ long result;
+ if (blockAvailable > SIZE_LONG) {
+ result = _currentBlock.readLongLE();
+ } else {
+ DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+ if (blockAvailable == SIZE_LONG) {
+ result = _currentBlock.readLongLE();
+ } else {
+ result = nextBlock.readLongLE(_currentBlock, blockAvailable);
+ }
+ _currentBlock = nextBlock;
+ }
+ _current_offset += SIZE_LONG;
+ return result;
+ }
+
+ @Override
+ public int readInt() {
+ checkAvaliable(SIZE_INT);
+ int blockAvailable = _currentBlock.available();
+ int result;
+ if (blockAvailable > SIZE_INT) {
+ result = _currentBlock.readIntLE();
+ } else {
+ DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+ if (blockAvailable == SIZE_INT) {
+ result = _currentBlock.readIntLE();
+ } else {
+ result = nextBlock.readIntLE(_currentBlock, blockAvailable);
+ }
+ _currentBlock = nextBlock;
+ }
+ _current_offset += SIZE_INT;
+ return result;
+ }
+
+ @Override
+ public int readUShort() {
+ checkAvaliable(SIZE_SHORT);
+ int blockAvailable = _currentBlock.available();
+ int result;
+ if (blockAvailable > SIZE_SHORT) {
+ result = _currentBlock.readUShortLE();
+ } else {
+ DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+ if (blockAvailable == SIZE_SHORT) {
+ result = _currentBlock.readUShortLE();
+ } else {
+ result = nextBlock.readUShortLE(_currentBlock);
+ }
+ _currentBlock = nextBlock;
+ }
+ _current_offset += SIZE_SHORT;
+ return result;
+ }
+
+ @Override
+ public int readUByte() {
+ checkAvaliable(1);
+ int result = _currentBlock.readUByte();
+ _current_offset++;
+ if (_currentBlock.available() < 1) {
+ _currentBlock = getDataInputBlock(_current_offset);
+ }
+ return result;
+ }
+}
Added: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java?rev=1053791&view=auto
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java (added)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10Native.java Thu Dec 30 02:35:06 2010
@@ -0,0 +1,279 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.filesystem;
+
+import org.apache.poi.util.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Represents an Ole10Native record which is wrapped around certain binary
+ * files being embedded in OLE2 documents.
+ *
+ * @author Rainer Schwarze
+ */
+public class Ole10Native {
+ // (the fields as they appear in the raw record:)
+ private final int totalSize; // 4 bytes, total size of record not including this field
+ private short flags1; // 2 bytes, unknown, mostly [02 00]
+ private final String label; // ASCIIZ, stored in this field without the terminating zero
+ private final String fileName; // ASCIIZ, stored in this field without the terminating zero
+ private short flags2; // 2 bytes, unknown, mostly [00 00]
+ // private byte unknown1Length; // 1 byte, specifying the length of the following byte array (unknown1)
+ private byte[] unknown1; // see below
+ private byte[] unknown2; // 3 bytes, unknown, mostly [00 00 00]
+ private final String command; // ASCIIZ, stored in this field without the terminating zero
+ private final int dataSize; // 4 bytes (if space), size of following buffer
+ private final byte[] dataBuffer; // varying size, the actual native data
+ private short flags3; // some final flags? or zero terminators?, sometimes not there
+ public static final String OLE10_NATIVE = "\u0001Ole10Native";
+
+ /**
+ * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
+ * to include a stream "{01}Ole10Native" which contains the actual
+ * data relevant for this class.
+ *
+ * @param poifs POI Filesystem object
+ * @return Returns an instance of this class
+ * @throws IOException on IO error
+ * @throws Ole10NativeException on invalid or unexcepted data format
+ */
+ public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {
+ boolean plain = false;
+
+ try {
+ poifs.getRoot().getEntry("\u0001Ole10ItemName");
+ plain = true;
+ } catch (FileNotFoundException ex) {
+ plain = false;
+ }
+
+ DocumentInputStream dis = poifs.createDocumentInputStream(OLE10_NATIVE);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ IOUtils.copy(dis, bos);
+ byte[] data = bos.toByteArray();
+
+ return new Ole10Native(data, 0, plain);
+ }
+
+ /**
+ * Creates an instance and fills the fields based on the data in the given buffer.
+ *
+ * @param data The buffer containing the Ole10Native record
+ * @param offset The start offset of the record in the buffer
+ * @throws Ole10NativeException on invalid or unexcepted data format
+ */
+ public Ole10Native(byte[] data, int offset) throws Ole10NativeException {
+ this(data, offset, false);
+ }
+ /**
+ * Creates an instance and fills the fields based on the data in the given buffer.
+ *
+ * @param data The buffer containing the Ole10Native record
+ * @param offset The start offset of the record in the buffer
+ * @param plain Specified 'plain' format without filename
+ * @throws Ole10NativeException on invalid or unexcepted data format
+ */
+ public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {
+ int ofs = offset; // current offset, initialized to start
+
+ if (data.length<offset+2) {
+ throw new Ole10NativeException("data is too small");
+ }
+
+ totalSize = LittleEndian.getInt(data, ofs);
+ ofs += LittleEndianConsts.INT_SIZE;
+
+ if (plain) {
+ dataBuffer = new byte[totalSize-4];
+ System.arraycopy(data, 4, dataBuffer, 0, dataBuffer.length);
+ dataSize = totalSize - 4;
+
+ byte[] oleLabel = new byte[8];
+ System.arraycopy(dataBuffer, 0, oleLabel, 0, Math.min(dataBuffer.length, 8));
+ label = "ole-"+ HexDump.toHex(oleLabel);
+ fileName = label;
+ command = label;
+ } else {
+ flags1 = LittleEndian.getShort(data, ofs);
+ ofs += LittleEndianConsts.SHORT_SIZE;
+ int len = getStringLength(data, ofs);
+ label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
+ ofs += len;
+ len = getStringLength(data, ofs);
+ fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
+ ofs += len;
+ flags2 = LittleEndian.getShort(data, ofs);
+ ofs += LittleEndianConsts.SHORT_SIZE;
+ len = LittleEndian.getUnsignedByte(data, ofs);
+ unknown1 = new byte[len];
+ ofs += len;
+ len = 3;
+ unknown2 = new byte[len];
+ ofs += len;
+ len = getStringLength(data, ofs);
+ command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
+ ofs += len;
+
+ if (totalSize + LittleEndianConsts.INT_SIZE - ofs > LittleEndianConsts.INT_SIZE) {
+ dataSize = LittleEndian.getInt(data, ofs);
+ ofs += LittleEndianConsts.INT_SIZE;
+
+ if (dataSize > totalSize || dataSize<0) {
+ throw new Ole10NativeException("Invalid Ole10Native");
+ }
+
+ dataBuffer = new byte[dataSize];
+ System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
+ ofs += dataSize;
+
+ if (unknown1.length > 0) {
+ flags3 = LittleEndian.getShort(data, ofs);
+ ofs += LittleEndianConsts.SHORT_SIZE;
+ } else {
+ flags3 = 0;
+ }
+ } else {
+ throw new Ole10NativeException("Invalid Ole10Native");
+ }
+ }
+ }
+
+ /*
+ * Helper - determine length of zero terminated string (ASCIIZ).
+ */
+ private static int getStringLength(byte[] data, int ofs) {
+ int len = 0;
+ while (len+ofs<data.length && data[ofs + len] != 0) {
+ len++;
+ }
+ len++;
+ return len;
+ }
+
+ /**
+ * Returns the value of the totalSize field - the total length of the structure
+ * is totalSize + 4 (value of this field + size of this field).
+ *
+ * @return the totalSize
+ */
+ public int getTotalSize() {
+ return totalSize;
+ }
+
+ /**
+ * Returns flags1 - currently unknown - usually 0x0002.
+ *
+ * @return the flags1
+ */
+ public short getFlags1() {
+ return flags1;
+ }
+
+ /**
+ * Returns the label field - usually the name of the file (without directory) but
+ * probably may be any name specified during packaging/embedding the data.
+ *
+ * @return the label
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Returns the fileName field - usually the name of the file being embedded
+ * including the full path.
+ *
+ * @return the fileName
+ */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Returns flags2 - currently unknown - mostly 0x0000.
+ *
+ * @return the flags2
+ */
+ public short getFlags2() {
+ return flags2;
+ }
+
+ /**
+ * Returns unknown1 field - currently unknown.
+ *
+ * @return the unknown1
+ */
+ public byte[] getUnknown1() {
+ return unknown1;
+ }
+
+ /**
+ * Returns the unknown2 field - currently being a byte[3] - mostly {0, 0, 0}.
+ *
+ * @return the unknown2
+ */
+ public byte[] getUnknown2() {
+ return unknown2;
+ }
+
+ /**
+ * Returns the command field - usually the name of the file being embedded
+ * including the full path, may be a command specified during embedding the file.
+ *
+ * @return the command
+ */
+ public String getCommand() {
+ return command;
+ }
+
+ /**
+ * Returns the size of the embedded file. If the size is 0 (zero), no data has been
+ * embedded. To be sure, that no data has been embedded, check whether
+ * {@link #getDataBuffer()} returns <code>null</code>.
+ *
+ * @return the dataSize
+ */
+ public int getDataSize() {
+ return dataSize;
+ }
+
+ /**
+ * Returns the buffer containing the embedded file's data, or <code>null</code>
+ * if no data was embedded. Note that an embedding may provide information about
+ * the data, but the actual data is not included. (So label, filename etc. are
+ * available, but this method returns <code>null</code>.)
+ *
+ * @return the dataBuffer
+ */
+ public byte[] getDataBuffer() {
+ return dataBuffer;
+ }
+
+ /**
+ * Returns the flags3 - currently unknown.
+ *
+ * @return the flags3
+ */
+ public short getFlags3() {
+ return flags3;
+ }
+}
Added: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java?rev=1053791&view=auto
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java (added)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/Ole10NativeException.java Thu Dec 30 02:35:06 2010
@@ -0,0 +1,24 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.filesystem;
+
+public class Ole10NativeException extends Exception {
+ public Ole10NativeException(String message) {
+ super(message);
+ }
+}
Modified: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java?rev=1053791&r1=1053790&r2=1053791&view=diff
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java (original)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java Thu Dec 30 02:35:06 2010
@@ -1,4 +1,3 @@
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -15,21 +14,27 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.filesystem;
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DocumentProperty;
import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.storage.BlockWritable;
-import org.apache.poi.poifs.storage.ListManagedBlock;
+import org.apache.poi.poifs.storage.DataInputBlock;
import org.apache.poi.poifs.storage.DocumentBlock;
+import org.apache.poi.poifs.storage.ListManagedBlock;
import org.apache.poi.poifs.storage.RawDataBlock;
import org.apache.poi.poifs.storage.SmallDocumentBlock;
import org.apache.poi.util.HexDump;
@@ -39,595 +44,525 @@ import org.apache.poi.util.HexDump;
*
* @author Marc Johnson (mjohnson at apache dot org)
*/
-
-public class POIFSDocument
- implements BATManaged, BlockWritable, POIFSViewable
-{
- private DocumentProperty _property;
- private int _size;
-
- // one of these stores will be valid
- private SmallBlockStore _small_store;
- private BigBlockStore _big_store;
-
- /**
- * Constructor from large blocks
- *
- * @param name the name of the POIFSDocument
- * @param blocks the big blocks making up the POIFSDocument
- * @param length the actual length of the POIFSDocument
- *
- * @exception IOException
- */
-
- public POIFSDocument(final String name, final RawDataBlock [] blocks,
- final int length)
- throws IOException
- {
- _size = length;
- _big_store = new BigBlockStore(blocks);
- _property = new DocumentProperty(name, _size);
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- _property.setDocument(this);
- }
-
- /**
- * Constructor from small blocks
- *
- * @param name the name of the POIFSDocument
- * @param blocks the small blocks making up the POIFSDocument
- * @param length the actual length of the POIFSDocument
- */
-
- public POIFSDocument(final String name,
- final SmallDocumentBlock [] blocks, final int length)
- {
- _size = length;
- try
- {
- _big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
- }
- catch (IOException ignored)
- {
-
- // can't happen with that constructor
- }
- _property = new DocumentProperty(name, _size);
- _small_store = new SmallBlockStore(blocks);
- _property.setDocument(this);
- }
-
- /**
- * Constructor from small blocks
- *
- * @param name the name of the POIFSDocument
- * @param blocks the small blocks making up the POIFSDocument
- * @param length the actual length of the POIFSDocument
- *
- * @exception IOException
- */
-
- public POIFSDocument(final String name, final ListManagedBlock [] blocks,
- final int length)
- throws IOException
- {
- _size = length;
- _property = new DocumentProperty(name, _size);
- _property.setDocument(this);
- if (Property.isSmall(_size))
- {
- _big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
- _small_store = new SmallBlockStore(blocks);
- }
- else
- {
- _big_store = new BigBlockStore(blocks);
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- }
- }
-
- /**
- * Constructor
- *
- * @param name the name of the POIFSDocument
- * @param stream the InputStream we read data from
- *
- * @exception IOException thrown on read errors
- */
-
- public POIFSDocument(final String name, final InputStream stream)
- throws IOException
- {
- List blocks = new ArrayList();
-
- _size = 0;
- while (true)
- {
- DocumentBlock block = new DocumentBlock(stream);
- int blockSize = block.size();
-
- if (blockSize > 0)
- {
- blocks.add(block);
- _size += blockSize;
- }
- if (block.partiallyRead())
- {
- break;
- }
- }
- DocumentBlock[] bigBlocks =
- ( DocumentBlock [] ) blocks.toArray(new DocumentBlock[ 0 ]);
-
- _big_store = new BigBlockStore(bigBlocks);
- _property = new DocumentProperty(name, _size);
- _property.setDocument(this);
- if (_property.shouldUseSmallBlocks())
- {
- _small_store =
- new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks,
- _size));
- _big_store = new BigBlockStore(new DocumentBlock[ 0 ]);
- }
- else
- {
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- }
- }
-
- /**
- * Constructor
- *
- * @param name the name of the POIFSDocument
- * @param size the length of the POIFSDocument
- * @param path the path of the POIFSDocument
- * @param writer the writer who will eventually write the document
- * contents
- *
- * @exception IOException thrown on read errors
- */
-
- public POIFSDocument(final String name, final int size,
- final POIFSDocumentPath path,
- final POIFSWriterListener writer)
- throws IOException
- {
- _size = size;
- _property = new DocumentProperty(name, _size);
- _property.setDocument(this);
- if (_property.shouldUseSmallBlocks())
- {
- _small_store = new SmallBlockStore(path, name, size, writer);
- _big_store = new BigBlockStore(new Object[ 0 ]);
- }
- else
- {
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- _big_store = new BigBlockStore(path, name, size, writer);
- }
- }
-
- /**
- * return the array of SmallDocumentBlocks used
- *
- * @return array of SmallDocumentBlocks; may be empty, cannot be null
- */
-
- public BlockWritable [] getSmallBlocks()
- {
- return _small_store.getBlocks();
- }
-
- /**
- * @return size of the document
- */
-
- public int getSize()
- {
- return _size;
- }
-
- /**
- * read data from the internal stores
- *
- * @param buffer the buffer to write to
- * @param offset the offset into our storage to read from
- */
-
- void read(final byte [] buffer, final int offset)
- {
- if (_property.shouldUseSmallBlocks())
- {
- SmallDocumentBlock.read(_small_store.getBlocks(), buffer, offset);
- }
- else
- {
- DocumentBlock.read(_big_store.getBlocks(), buffer, offset);
- }
- }
-
- /**
- * Get the DocumentProperty
- *
- * @return the instance's DocumentProperty
- */
-
- DocumentProperty getDocumentProperty()
- {
- return _property;
- }
-
- /* ********** START implementation of BlockWritable ********** */
-
- /**
- * Write the storage to an OutputStream
- *
- * @param stream the OutputStream to which the stored data should
- * be written
- *
- * @exception IOException on problems writing to the specified
- * stream
- */
-
- public void writeBlocks(final OutputStream stream)
- throws IOException
- {
- _big_store.writeBlocks(stream);
- }
-
- /* ********** END implementation of BlockWritable ********** */
- /* ********** START implementation of BATManaged ********** */
-
- /**
- * Return the number of BigBlock's this instance uses
- *
- * @return count of BigBlock instances
- */
-
- public int countBlocks()
- {
- return _big_store.countBlocks();
- }
-
- /**
- * Set the start block for this instance
- *
- * @param index index into the array of blocks making up the
- * filesystem
- */
-
- public void setStartBlock(final int index)
- {
- _property.setStartBlock(index);
- }
-
- /* ********** END implementation of BATManaged ********** */
- /* ********** START begin implementation of POIFSViewable ********** */
-
- /**
- * Get an array of objects, some of which may implement
- * POIFSViewable
- *
- * @return an array of Object; may not be null, but may be empty
- */
-
- public Object [] getViewableArray()
- {
- Object[] results = new Object[ 1 ];
- String result;
-
- try
- {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- BlockWritable[] blocks = null;
-
- if (_big_store.isValid())
- {
- blocks = _big_store.getBlocks();
- }
- else if (_small_store.isValid())
- {
- blocks = _small_store.getBlocks();
- }
- if (blocks != null)
- {
- for (int k = 0; k < blocks.length; k++)
- {
- blocks[ k ].writeBlocks(output);
- }
- byte[] data = output.toByteArray();
-
- if (data.length > _property.getSize())
- {
- byte[] tmp = new byte[ _property.getSize() ];
-
- System.arraycopy(data, 0, tmp, 0, tmp.length);
- data = tmp;
- }
- output = new ByteArrayOutputStream();
- HexDump.dump(data, 0, output, 0);
- result = output.toString();
- }
- else
- {
- result = "<NO DATA>";
- }
- }
- catch (IOException e)
- {
- result = e.getMessage();
- }
- results[ 0 ] = result;
- return results;
- }
-
- /**
- * Get an Iterator of objects, some of which may implement
- * POIFSViewable
- *
- * @return an Iterator; may not be null, but may have an empty
- * back end store
- */
-
- public Iterator getViewableIterator()
- {
- return Collections.EMPTY_LIST.iterator();
- }
-
- /**
- * Give viewers a hint as to whether to call getViewableArray or
- * getViewableIterator
- *
- * @return true if a viewer should call getViewableArray, false if
- * a viewer should call getViewableIterator
- */
-
- public boolean preferArray()
- {
- return true;
- }
-
- /**
- * Provides a short description of the object, to be used when a
- * POIFSViewable object has not provided its contents.
- *
- * @return short description
- */
-
- public String getShortDescription()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("Document: \"").append(_property.getName())
- .append("\"");
- buffer.append(" size = ").append(getSize());
- return buffer.toString();
- }
-
- /* ********** END begin implementation of POIFSViewable ********** */
- private class SmallBlockStore
- {
- private SmallDocumentBlock[] smallBlocks;
- private POIFSDocumentPath path;
- private String name;
- private int size;
- private POIFSWriterListener writer;
-
- /**
- * Constructor
- *
- * @param blocks blocks to construct the store from
- */
-
- SmallBlockStore(final Object [] blocks)
- {
- smallBlocks = new SmallDocumentBlock[ blocks.length ];
- for (int j = 0; j < blocks.length; j++)
- {
- smallBlocks[ j ] = ( SmallDocumentBlock ) blocks[ j ];
- }
- this.path = null;
- this.name = null;
- this.size = -1;
- this.writer = null;
- }
-
- /**
- * Constructor for a small block store that will be written
- * later
- *
- * @param path path of the document
- * @param name name of the document
- * @param size length of the document
- * @param writer the object that will eventually write the document
- */
-
- SmallBlockStore(final POIFSDocumentPath path, final String name,
- final int size, final POIFSWriterListener writer)
- {
- smallBlocks = new SmallDocumentBlock[ 0 ];
- this.path = path;
- this.name = name;
- this.size = size;
- this.writer = writer;
- }
-
- /**
- * @return true if this store is a valid source of data
- */
-
- boolean isValid()
- {
- return ((smallBlocks.length > 0) || (writer != null));
- }
-
- /**
- * @return the SmallDocumentBlocks
- */
-
- BlockWritable [] getBlocks()
- {
- if (isValid() && (writer != null))
- {
- ByteArrayOutputStream stream =
- new ByteArrayOutputStream(size);
- DocumentOutputStream dstream =
- new DocumentOutputStream(stream, size);
-
- writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
- path, name, size));
- smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(),
- size);
- }
- return smallBlocks;
- }
- } // end private class SmallBlockStore
-
- private class BigBlockStore
- {
- private DocumentBlock[] bigBlocks;
- private POIFSDocumentPath path;
- private String name;
- private int size;
- private POIFSWriterListener writer;
-
- /**
- * Constructor
- *
- * @param blocks the blocks making up the store
- *
- * @exception IOException on I/O error
- */
-
- BigBlockStore(final Object [] blocks)
- throws IOException
- {
- bigBlocks = new DocumentBlock[ blocks.length ];
- for (int j = 0; j < blocks.length; j++)
- {
- if (blocks[ j ] instanceof DocumentBlock)
- {
- bigBlocks[ j ] = ( DocumentBlock ) blocks[ j ];
- }
- else
- {
- bigBlocks[ j ] =
- new DocumentBlock(( RawDataBlock ) blocks[ j ]);
- }
- }
- this.path = null;
- this.name = null;
- this.size = -1;
- this.writer = null;
- }
-
- /**
- * Constructor for a big block store that will be written
- * later
- *
- * @param path path of the document
- * @param name name of the document
- * @param size length of the document
- * @param writer the object that will eventually write the
- * document
- */
-
- BigBlockStore(final POIFSDocumentPath path, final String name,
- final int size, final POIFSWriterListener writer)
- {
- bigBlocks = new DocumentBlock[ 0 ];
- this.path = path;
- this.name = name;
- this.size = size;
- this.writer = writer;
- }
-
- /**
- * @return true if this store is a valid source of data
- */
-
- boolean isValid()
- {
- return ((bigBlocks.length > 0) || (writer != null));
- }
-
- /**
- * @return the DocumentBlocks
- */
-
- DocumentBlock [] getBlocks()
- {
- if (isValid() && (writer != null))
- {
- ByteArrayOutputStream stream =
- new ByteArrayOutputStream(size);
- DocumentOutputStream dstream =
- new DocumentOutputStream(stream, size);
-
- writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
- path, name, size));
- bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
- }
- return bigBlocks;
- }
-
- /**
- * write the blocks to a stream
- *
- * @param stream the stream to which the data is to be written
- *
- * @exception IOException on error
- */
-
- 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()
- * POIFSConstants
- .BIG_BLOCK_SIZE, DocumentBlock
- .getFillByte());
- }
- else
- {
- for (int k = 0; k < bigBlocks.length; k++)
- {
- bigBlocks[ k ].writeBlocks(stream);
- }
- }
- }
- }
-
- /**
- * @return number of big blocks making up this document
- */
-
- int countBlocks()
- {
- int rval = 0;
-
- if (isValid())
- {
- if (writer != null)
- {
- rval = (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
- / POIFSConstants.BIG_BLOCK_SIZE;
- }
- else
- {
- rval = bigBlocks.length;
- }
- }
- return rval;
- }
- } // end private class BigBlockStore
-} // end class POIFSDocument
-
+public final class POIFSDocument implements BATManaged, BlockWritable, POIFSViewable {
+ private static final DocumentBlock[] EMPTY_BIG_BLOCK_ARRAY = { };
+ private static final SmallDocumentBlock[] EMPTY_SMALL_BLOCK_ARRAY = { };
+ private DocumentProperty _property;
+ private int _size;
+
+ private final POIFSBigBlockSize _bigBigBlockSize;
+
+ // one of these stores will be valid
+ private SmallBlockStore _small_store;
+ private BigBlockStore _big_store;
+
+ /**
+ * Constructor from large blocks
+ *
+ * @param name the name of the POIFSDocument
+ * @param blocks the big blocks making up the POIFSDocument
+ * @param length the actual length of the POIFSDocument
+ */
+ public POIFSDocument(String name, RawDataBlock[] blocks, int length) throws IOException {
+ _size = length;
+ if(blocks.length == 0) {
+ _bigBigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;
+ } else {
+ _bigBigBlockSize = (blocks[0].getBigBlockSize() == POIFSConstants.SMALLER_BIG_BLOCK_SIZE ?
+ POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS :
+ POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS
+ );
+ }
+
+ _big_store = new BigBlockStore(_bigBigBlockSize, convertRawBlocksToBigBlocks(blocks));
+ _property = new DocumentProperty(name, _size);
+ _small_store = new SmallBlockStore(_bigBigBlockSize, EMPTY_SMALL_BLOCK_ARRAY);
+ _property.setDocument(this);
+ }
+
+ // TODO - awkward typing going on here
+ private static DocumentBlock[] convertRawBlocksToBigBlocks(ListManagedBlock[] blocks) throws IOException {
+ DocumentBlock[] result = new DocumentBlock[blocks.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = new DocumentBlock((RawDataBlock)blocks[i]);
+ }
+ return result;
+ }
+ private static SmallDocumentBlock[] convertRawBlocksToSmallBlocks(ListManagedBlock[] blocks) {
+ if (blocks instanceof SmallDocumentBlock[]) {
+ return (SmallDocumentBlock[]) blocks;
+ }
+ SmallDocumentBlock[] result = new SmallDocumentBlock[blocks.length];
+ System.arraycopy(blocks, 0, result, 0, blocks.length);
+ return result;
+ }
+
+ /**
+ * Constructor from small blocks
+ *
+ * @param name the name of the POIFSDocument
+ * @param blocks the small blocks making up the POIFSDocument
+ * @param length the actual length of the POIFSDocument
+ */
+ public POIFSDocument(String name, SmallDocumentBlock[] blocks, int length) {
+ _size = length;
+
+ if(blocks.length == 0) {
+ _bigBigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;
+ } else {
+ _bigBigBlockSize = blocks[0].getBigBlockSize();
+ }
+
+ _big_store = new BigBlockStore(_bigBigBlockSize, EMPTY_BIG_BLOCK_ARRAY);
+ _property = new DocumentProperty(name, _size);
+ _small_store = new SmallBlockStore(_bigBigBlockSize, blocks);
+ _property.setDocument(this);
+ }
+
+ /**
+ * Constructor from small blocks
+ *
+ * @param name the name of the POIFSDocument
+ * @param blocks the small blocks making up the POIFSDocument
+ * @param length the actual length of the POIFSDocument
+ */
+ public POIFSDocument(String name, POIFSBigBlockSize bigBlockSize, ListManagedBlock[] blocks, int length) throws IOException {
+ _size = length;
+ _bigBigBlockSize = bigBlockSize;
+ _property = new DocumentProperty(name, _size);
+ _property.setDocument(this);
+ if (Property.isSmall(_size)) {
+ _big_store = new BigBlockStore(bigBlockSize,EMPTY_BIG_BLOCK_ARRAY);
+ _small_store = new SmallBlockStore(bigBlockSize,convertRawBlocksToSmallBlocks(blocks));
+ } else {
+ _big_store = new BigBlockStore(bigBlockSize,convertRawBlocksToBigBlocks(blocks));
+ _small_store = new SmallBlockStore(bigBlockSize,EMPTY_SMALL_BLOCK_ARRAY);
+ }
+ }
+ public POIFSDocument(String name, ListManagedBlock[] blocks, int length) throws IOException {
+ this(name, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, blocks, length);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param name the name of the POIFSDocument
+ * @param stream the InputStream we read data from
+ */
+ public POIFSDocument(String name, POIFSBigBlockSize bigBlockSize, InputStream stream) throws IOException {
+ List<DocumentBlock> blocks = new ArrayList<DocumentBlock>();
+
+ _size = 0;
+ _bigBigBlockSize = bigBlockSize;
+ while (true) {
+ DocumentBlock block = new DocumentBlock(stream, bigBlockSize);
+ int blockSize = block.size();
+
+ if (blockSize > 0) {
+ blocks.add(block);
+ _size += blockSize;
+ }
+ if (block.partiallyRead()) {
+ break;
+ }
+ }
+ DocumentBlock[] bigBlocks = blocks.toArray(new DocumentBlock[blocks.size()]);
+
+ _big_store = new BigBlockStore(bigBlockSize,bigBlocks);
+ _property = new DocumentProperty(name, _size);
+ _property.setDocument(this);
+ if (_property.shouldUseSmallBlocks()) {
+ _small_store = new SmallBlockStore(bigBlockSize,SmallDocumentBlock.convert(bigBlockSize,bigBlocks, _size));
+ _big_store = new BigBlockStore(bigBlockSize,new DocumentBlock[0]);
+ } else {
+ _small_store = new SmallBlockStore(bigBlockSize,EMPTY_SMALL_BLOCK_ARRAY);
+ }
+ }
+ public POIFSDocument(String name, InputStream stream) throws IOException {
+ this(name, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, stream);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param name the name of the POIFSDocument
+ * @param size the length of the POIFSDocument
+ * @param path the path of the POIFSDocument
+ * @param writer the writer who will eventually write the document contents
+ */
+ public POIFSDocument(String name, int size, POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path, POIFSWriterListener writer) {
+ _size = size;
+ _bigBigBlockSize = bigBlockSize;
+ _property = new DocumentProperty(name, _size);
+ _property.setDocument(this);
+ if (_property.shouldUseSmallBlocks()) {
+ _small_store = new SmallBlockStore(_bigBigBlockSize, path, name, size, writer);
+ _big_store = new BigBlockStore(_bigBigBlockSize, EMPTY_BIG_BLOCK_ARRAY);
+ } else {
+ _small_store = new SmallBlockStore(_bigBigBlockSize, EMPTY_SMALL_BLOCK_ARRAY);
+ _big_store = new BigBlockStore(_bigBigBlockSize, path, name, size, writer);
+ }
+ }
+ public POIFSDocument(String name, int size, POIFSDocumentPath path, POIFSWriterListener writer) {
+ this(name, size, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, path, writer);
+ }
+
+ /**
+ * @return array of SmallDocumentBlocks; may be empty, cannot be null
+ */
+ public BlockWritable[] getSmallBlocks() {
+ return _small_store.getBlocks();
+ }
+
+ /**
+ * @return size of the document
+ */
+ public int getSize() {
+ return _size;
+ }
+
+ /**
+ * read data from the internal stores
+ *
+ * @param buffer the buffer to write to
+ * @param offset the offset into our storage to read from
+ * This method is currently (Oct 2008) only used by test code. Perhaps it can be deleted
+ */
+ void read(byte[] buffer, int offset) {
+ int len = buffer.length;
+
+ DataInputBlock currentBlock = getDataInputBlock(offset);
+
+ int blockAvailable = currentBlock.available();
+ if (blockAvailable > len) {
+ currentBlock.readFully(buffer, 0, len);
+ return;
+ }
+ // else read big amount in chunks
+ int remaining = len;
+ int writePos = 0;
+ int currentOffset = offset;
+ while (remaining > 0) {
+ boolean blockIsExpiring = remaining >= blockAvailable;
+ int reqSize;
+ if (blockIsExpiring) {
+ reqSize = blockAvailable;
+ } else {
+ reqSize = remaining;
+ }
+ currentBlock.readFully(buffer, writePos, reqSize);
+ remaining-=reqSize;
+ writePos+=reqSize;
+ currentOffset += reqSize;
+ if (blockIsExpiring) {
+ if (currentOffset == _size) {
+ if (remaining > 0) {
+ throw new IllegalStateException("reached end of document stream unexpectedly");
+ }
+ currentBlock = null;
+ break;
+ }
+ currentBlock = getDataInputBlock(currentOffset);
+ blockAvailable = currentBlock.available();
+ }
+ }
+ }
+
+ /**
+ * @return <code>null</code> if <tt>offset</tt> points to the end of the document stream
+ */
+ DataInputBlock getDataInputBlock(int offset) {
+ if (offset >= _size) {
+ if (offset > _size) {
+ throw new RuntimeException("Request for Offset " + offset + " doc size is " + _size);
+ }
+ return null;
+ }
+ if (_property.shouldUseSmallBlocks()) {
+ return SmallDocumentBlock.getDataInputBlock(_small_store.getBlocks(), offset);
+ }
+ return DocumentBlock.getDataInputBlock(_big_store.getBlocks(), offset);
+ }
+
+ /**
+ * @return the instance's DocumentProperty
+ */
+
+ DocumentProperty getDocumentProperty() {
+ return _property;
+ }
+
+ /* ********** START implementation of BlockWritable ********** */
+
+ /**
+ * Write the storage to an OutputStream
+ *
+ * @param stream the OutputStream to which the stored data should be written
+ */
+ public void writeBlocks(OutputStream stream) throws IOException {
+ _big_store.writeBlocks(stream);
+ }
+
+ /* ********** END implementation of BlockWritable ********** */
+ /* ********** START implementation of BATManaged ********** */
+
+ /**
+ * Return the number of BigBlock's this instance uses
+ *
+ * @return count of BigBlock instances
+ */
+ public int countBlocks() {
+ return _big_store.countBlocks();
+ }
+
+ /**
+ * Set the start block for this instance
+ *
+ * @param index index into the array of blocks making up the filesystem
+ */
+ public void setStartBlock(int index) {
+ _property.setStartBlock(index);
+ }
+
+ /* ********** END implementation of BATManaged ********** */
+ /* ********** START begin implementation of POIFSViewable ********** */
+
+ /**
+ * Get an array of objects, some of which may implement POIFSViewable
+ *
+ * @return an array of Object; may not be null, but may be empty
+ */
+ public Object[] getViewableArray() {
+ Object[] results = new Object[1];
+ String result;
+
+ try {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ BlockWritable[] blocks = null;
+
+ if (_big_store.isValid()) {
+ blocks = _big_store.getBlocks();
+ } else if (_small_store.isValid()) {
+ blocks = _small_store.getBlocks();
+ }
+ if (blocks != null) {
+ for (int k = 0; k < blocks.length; k++) {
+ blocks[k].writeBlocks(output);
+ }
+ byte[] data = output.toByteArray();
+
+ if (data.length > _property.getSize()) {
+ byte[] tmp = new byte[_property.getSize()];
+
+ System.arraycopy(data, 0, tmp, 0, tmp.length);
+ data = tmp;
+ }
+ output = new ByteArrayOutputStream();
+ HexDump.dump(data, 0, output, 0);
+ result = output.toString();
+ } else {
+ result = "<NO DATA>";
+ }
+ } catch (IOException e) {
+ result = e.getMessage();
+ }
+ results[0] = result;
+ return results;
+ }
+
+ /**
+ * Get an Iterator of objects, some of which may implement POIFSViewable
+ *
+ * @return an Iterator; may not be null, but may have an empty back end
+ * store
+ */
+ public Iterator getViewableIterator() {
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ /**
+ * Give viewers a hint as to whether to call getViewableArray or
+ * getViewableIterator
+ *
+ * @return <code>true</code> if a viewer should call getViewableArray,
+ * <code>false</code> if a viewer should call getViewableIterator
+ */
+ public boolean preferArray() {
+ return true;
+ }
+
+ /**
+ * Provides a short description of the object, to be used when a
+ * POIFSViewable object has not provided its contents.
+ *
+ * @return short description
+ */
+ public String getShortDescription() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("Document: \"").append(_property.getName()).append("\"");
+ buffer.append(" size = ").append(getSize());
+ return buffer.toString();
+ }
+
+ /* ********** END begin implementation of POIFSViewable ********** */
+ private static final class SmallBlockStore {
+ private SmallDocumentBlock[] _smallBlocks;
+ private final POIFSDocumentPath _path;
+ private final String _name;
+ private final int _size;
+ private final POIFSWriterListener _writer;
+ private final POIFSBigBlockSize _bigBlockSize;
+
+ /**
+ * Constructor
+ *
+ * @param blocks blocks to construct the store from
+ */
+ SmallBlockStore(POIFSBigBlockSize bigBlockSize, SmallDocumentBlock[] blocks) {
+ _bigBlockSize = bigBlockSize;
+ _smallBlocks = blocks.clone();
+ this._path = null;
+ this._name = null;
+ this._size = -1;
+ this._writer = null;
+ }
+
+ /**
+ * Constructor for a small block store that will be written later
+ *
+ * @param path path of the document
+ * @param name name of the document
+ * @param size length of the document
+ * @param writer the object that will eventually write the document
+ */
+ SmallBlockStore(POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path,
+ String name, int size, POIFSWriterListener writer) {
+ _bigBlockSize = bigBlockSize;
+ _smallBlocks = new SmallDocumentBlock[0];
+ this._path = path;
+ this._name = name;
+ this._size = size;
+ this._writer = writer;
+ }
+
+ /**
+ * @return <code>true</code> if this store is a valid source of data
+ */
+ boolean isValid() {
+ return _smallBlocks.length > 0 || _writer != null;
+ }
+
+ /**
+ * @return the SmallDocumentBlocks
+ */
+ SmallDocumentBlock[] getBlocks() {
+ if (isValid() && _writer != null) {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(_size);
+ DocumentOutputStream dstream = new DocumentOutputStream(stream, _size);
+
+ _writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, _path, _name, _size));
+ _smallBlocks = SmallDocumentBlock.convert(_bigBlockSize, stream.toByteArray(), _size);
+ }
+ return _smallBlocks;
+ }
+ } // end private class SmallBlockStore
+
+ private static final class BigBlockStore {
+ private DocumentBlock[] bigBlocks;
+ private final POIFSDocumentPath _path;
+ private final String _name;
+ private final int _size;
+ private final POIFSWriterListener _writer;
+ private final POIFSBigBlockSize _bigBlockSize;
+
+ /**
+ * Constructor
+ *
+ * @param blocks the blocks making up the store
+ */
+ BigBlockStore(POIFSBigBlockSize bigBlockSize, DocumentBlock[] blocks) {
+ _bigBlockSize = bigBlockSize;
+ bigBlocks = blocks.clone();
+ _path = null;
+ _name = null;
+ _size = -1;
+ _writer = null;
+ }
+
+ /**
+ * Constructor for a big block store that will be written later
+ *
+ * @param path path of the document
+ * @param name name of the document
+ * @param size length of the document
+ * @param writer the object that will eventually write the document
+ */
+ BigBlockStore(POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path,
+ String name, int size, POIFSWriterListener writer) {
+ _bigBlockSize = bigBlockSize;
+ bigBlocks = new DocumentBlock[0];
+ _path = path;
+ _name = name;
+ _size = size;
+ _writer = writer;
+ }
+
+ /**
+ * @return <code>true</code> if this store is a valid source of data
+ */
+ boolean isValid() {
+ return bigBlocks.length > 0 || _writer != null;
+ }
+
+ /**
+ * @return the DocumentBlocks
+ */
+ DocumentBlock[] getBlocks() {
+ if (isValid() && _writer != null) {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(_size);
+ DocumentOutputStream dstream = new DocumentOutputStream(stream, _size);
+
+ _writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, _path, _name, _size));
+ bigBlocks = DocumentBlock.convert(_bigBlockSize, stream.toByteArray(), _size);
+ }
+ return bigBlocks;
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
+ }
+
+ /**
+ * @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;
+ }
+ } // end private class BigBlockStore
+}
Modified: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java?rev=1053791&r1=1053790&r2=1053791&view=diff
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java (original)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSDocumentPath.java Thu Dec 30 02:35:06 2010
@@ -21,6 +21,9 @@ package org.apache.poi.poifs.filesystem;
import java.io.File;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
/**
* Class POIFSDocumentPath
*
@@ -30,6 +33,8 @@ import java.io.File;
public class POIFSDocumentPath
{
+ private static final POILogger log = POILogFactory.getLogger(POIFSDocumentPath.class);
+
private String[] components;
private int hashcode = 0;
@@ -125,12 +130,17 @@ public class POIFSDocumentPath
{
for (int j = 0; j < components.length; j++)
{
- if ((components[ j ] == null)
- || (components[ j ].length() == 0))
+ if (components[ j ] == null)
{
throw new IllegalArgumentException(
- "components cannot contain null or empty strings");
+ "components cannot contain null");
+ }
+ if (components[ j ].length() == 0)
+ {
+ log.log(POILogger.WARN, "Directory under " + path + " has an empty name, " +
+ "not all OLE2 readers will handle this file correctly!");
}
+
this.components[ j + path.components.length ] =
components[ j ];
}
Modified: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java?rev=1053791&r1=1053790&r2=1053791&view=diff
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java (original)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java Thu Dec 30 02:35:06 2010
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
+
package org.apache.poi.poifs.filesystem;
@@ -31,6 +31,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import org.apache.poi.poifs.common.POIFSBigBlockSize;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DirectoryProperty;
@@ -42,11 +43,12 @@ import org.apache.poi.poifs.storage.Bloc
import org.apache.poi.poifs.storage.BlockList;
import org.apache.poi.poifs.storage.BlockWritable;
import org.apache.poi.poifs.storage.HeaderBlockConstants;
-import org.apache.poi.poifs.storage.HeaderBlockReader;
+import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.HeaderBlockWriter;
import org.apache.poi.poifs.storage.RawDataBlockList;
import org.apache.poi.poifs.storage.SmallBlockTableReader;
import org.apache.poi.poifs.storage.SmallBlockTableWriter;
+import org.apache.poi.util.CloseIgnoringInputStream;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LongField;
import org.apache.poi.util.POILogFactory;
@@ -64,47 +66,32 @@ public class POIFSFileSystem
{
private static final POILogger _logger =
POILogFactory.getLogger(POIFSFileSystem.class);
-
- private static final class CloseIgnoringInputStream extends InputStream {
- private final InputStream _is;
- public CloseIgnoringInputStream(InputStream is) {
- _is = is;
- }
- public int read() throws IOException {
- return _is.read();
- }
- public int read(byte[] b, int off, int len) throws IOException {
- return _is.read(b, off, len);
- }
- public void close() {
- // do nothing
- }
- }
-
/**
* Convenience method for clients that want to avoid the auto-close behaviour of the constructor.
*/
public static InputStream createNonClosingInputStream(InputStream is) {
return new CloseIgnoringInputStream(is);
}
-
+
private PropertyTable _property_table;
private List _documents;
private DirectoryNode _root;
-
+
/**
* What big block size the file uses. Most files
* use 512 bytes, but a few use 4096
*/
- private int bigBlockSize = POIFSConstants.BIG_BLOCK_SIZE;
+ private POIFSBigBlockSize bigBlockSize =
+ POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS;
/**
* Constructor, intended for writing
*/
public POIFSFileSystem()
{
- _property_table = new PropertyTable();
+ HeaderBlock header_block = new HeaderBlock(bigBlockSize);
+ _property_table = new PropertyTable(header_block);
_documents = new ArrayList();
_root = null;
}
@@ -112,20 +99,20 @@ public class POIFSFileSystem
/**
* Create a POIFSFileSystem from an <tt>InputStream</tt>. Normally the stream is read until
* EOF. The stream is always closed.<p/>
- *
- * Some streams are usable after reaching EOF (typically those that return <code>true</code>
- * for <tt>markSupported()</tt>). In the unlikely case that the caller has such a stream
+ *
+ * Some streams are usable after reaching EOF (typically those that return <code>true</code>
+ * for <tt>markSupported()</tt>). In the unlikely case that the caller has such a stream
* <i>and</i> needs to use it after this constructor completes, a work around is to wrap the
* stream in order to trap the <tt>close()</tt> call. A convenience method (
* <tt>createNonClosingInputStream()</tt>) has been provided for this purpose:
* <pre>
* InputStream wrappedStream = POIFSFileSystem.createNonClosingInputStream(is);
* HSSFWorkbook wb = new HSSFWorkbook(wrappedStream);
- * is.reset();
- * doSomethingElse(is);
+ * is.reset();
+ * doSomethingElse(is);
* </pre>
* Note also the special case of <tt>ByteArrayInputStream</tt> for which the <tt>close()</tt>
- * method does nothing.
+ * method does nothing.
* <pre>
* ByteArrayInputStream bais = ...
* HSSFWorkbook wb = new HSSFWorkbook(bais); // calls bais.close() !
@@ -144,49 +131,57 @@ public class POIFSFileSystem
this();
boolean success = false;
- HeaderBlockReader header_block_reader;
+ HeaderBlock header_block;
RawDataBlockList data_blocks;
try {
// read the header block from the stream
- header_block_reader = new HeaderBlockReader(stream);
- bigBlockSize = header_block_reader.getBigBlockSize();
-
+ header_block = new HeaderBlock(stream);
+ bigBlockSize = header_block.getBigBlockSize();
+
// read the rest of the stream into blocks
data_blocks = new RawDataBlockList(stream, bigBlockSize);
success = true;
} finally {
closeInputStream(stream, success);
}
-
+
// set up the block allocation table (necessary for the
// data_blocks to be manageable
- new BlockAllocationTableReader(header_block_reader.getBATCount(),
- header_block_reader.getBATArray(),
- header_block_reader.getXBATCount(),
- header_block_reader.getXBATIndex(),
+ new BlockAllocationTableReader(header_block.getBigBlockSize(),
+ header_block.getBATCount(),
+ header_block.getBATArray(),
+ header_block.getXBATCount(),
+ header_block.getXBATIndex(),
data_blocks);
// get property table from the document
PropertyTable properties =
- new PropertyTable(header_block_reader.getPropertyStart(),
- data_blocks);
+ new PropertyTable(header_block, data_blocks);
// init documents
- processProperties(SmallBlockTableReader
- .getSmallDocumentBlocks(data_blocks, properties
- .getRoot(), header_block_reader
- .getSBATStart()), data_blocks, properties.getRoot()
- .getChildren(), null);
+ processProperties(
+ SmallBlockTableReader.getSmallDocumentBlocks(
+ bigBlockSize, data_blocks, properties.getRoot(),
+ header_block.getSBATStart()
+ ),
+ data_blocks,
+ properties.getRoot().getChildren(),
+ null,
+ header_block.getPropertyStart()
+ );
+
+ // For whatever reason CLSID of root is always 0.
+ getRoot().setStorageClsid(properties.getRoot().getStorageClsid());
}
/**
* @param stream the stream to be closed
* @param success <code>false</code> if an exception is currently being thrown in the calling method
*/
private void closeInputStream(InputStream stream, boolean success) {
-
+
if(stream.markSupported() && !(stream instanceof ByteArrayInputStream)) {
- String msg = "POIFS is closing the supplied input stream of type ("
+ String msg = "POIFS is closing the supplied input stream of type ("
+ stream.getClass().getName() + ") which supports mark/reset. "
+ "This will be a problem for the caller if the stream will still be used. "
+ "If that is the case the caller should wrap the input stream to avoid this close logic. "
@@ -199,7 +194,7 @@ public class POIFSFileSystem
if(success) {
throw new RuntimeException(e);
}
- // else not success? Try block did not complete normally
+ // else not success? Try block did not complete normally
// just print stack trace and leave original ex to be thrown
e.printStackTrace();
}
@@ -207,15 +202,15 @@ public class POIFSFileSystem
/**
* Checks that the supplied InputStream (which MUST
- * support mark and reset, or be a PushbackInputStream)
+ * support mark and reset, or be a PushbackInputStream)
* has a POIFS (OLE2) header at the start of it.
* If your InputStream does not support mark / reset,
* then wrap it in a PushBackInputStream, then be
* sure to always use that, and not the original!
- * @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream
+ * @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream
*/
public static boolean hasPOIFSHeader(InputStream inp) throws IOException {
- // We want to peek at the first 8 bytes
+ // We want to peek at the first 8 bytes
inp.mark(8);
byte[] header = new byte[8];
@@ -229,7 +224,7 @@ public class POIFSFileSystem
} else {
inp.reset();
}
-
+
// Did it match the signature?
return (signature.get() == HeaderBlockConstants._signature);
}
@@ -288,7 +283,7 @@ public class POIFSFileSystem
{
return getRoot().createDirectory(name);
}
-
+
/**
* Write the filesystem out
*
@@ -307,11 +302,11 @@ public class POIFSFileSystem
// create the small block store, and the SBAT
SmallBlockTableWriter sbtw =
- new SmallBlockTableWriter(_documents, _property_table.getRoot());
+ new SmallBlockTableWriter(bigBlockSize, _documents, _property_table.getRoot());
// create the block allocation table
BlockAllocationTableWriter bat =
- new BlockAllocationTableWriter();
+ new BlockAllocationTableWriter(bigBlockSize);
// create a list of BATManaged objects: the documents plus the
// property table and the small block table
@@ -349,7 +344,7 @@ public class POIFSFileSystem
int batStartBlock = bat.createBlocks();
// get the extended block allocation table blocks
- HeaderBlockWriter header_block_writer = new HeaderBlockWriter();
+ HeaderBlockWriter header_block_writer = new HeaderBlockWriter(bigBlockSize);
BATBlock[] xbat_blocks =
header_block_writer.setBATBlocks(bat.countBlocks(),
batStartBlock);
@@ -491,7 +486,8 @@ public class POIFSFileSystem
private void processProperties(final BlockList small_blocks,
final BlockList big_blocks,
final Iterator properties,
- final DirectoryNode dir)
+ final DirectoryNode dir,
+ final int headerPropertiesStartAt)
throws IOException
{
while (properties.hasNext())
@@ -511,7 +507,8 @@ public class POIFSFileSystem
processProperties(
small_blocks, big_blocks,
- (( DirectoryProperty ) property).getChildren(), new_dir);
+ (( DirectoryProperty ) property).getChildren(),
+ new_dir, headerPropertiesStartAt);
}
else
{
@@ -522,14 +519,15 @@ public class POIFSFileSystem
if (property.shouldUseSmallBlocks())
{
document =
- new POIFSDocument(name, small_blocks
- .fetchBlocks(startBlock), size);
+ new POIFSDocument(name,
+ small_blocks.fetchBlocks(startBlock, headerPropertiesStartAt),
+ size);
}
else
{
document =
new POIFSDocument(name,
- big_blocks.fetchBlocks(startBlock),
+ big_blocks.fetchBlocks(startBlock, headerPropertiesStartAt),
size);
}
parent.createDocument(document);
@@ -552,10 +550,7 @@ public class POIFSFileSystem
{
return (( POIFSViewable ) getRoot()).getViewableArray();
}
- else
- {
- return new Object[ 0 ];
- }
+ return new Object[ 0 ];
}
/**
@@ -572,10 +567,7 @@ public class POIFSFileSystem
{
return (( POIFSViewable ) getRoot()).getViewableIterator();
}
- else
- {
- return Collections.EMPTY_LIST.iterator();
- }
+ return Collections.EMPTY_LIST.iterator();
}
/**
@@ -607,9 +599,15 @@ public class POIFSFileSystem
* @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
*/
public int getBigBlockSize() {
- return bigBlockSize;
+ return bigBlockSize.getBigBlockSize();
+ }
+ /**
+ * @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
+ */
+ public POIFSBigBlockSize getBigBlockSizeDetails() {
+ return bigBlockSize;
}
-
+
/* ********** END begin implementation of POIFSViewable ********** */
} // end public class POIFSFileSystem
Added: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/ByteArrayBackedDataSource.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/ByteArrayBackedDataSource.java?rev=1053791&view=auto
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/ByteArrayBackedDataSource.java (added)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/ByteArrayBackedDataSource.java Thu Dec 30 02:35:06 2010
@@ -0,0 +1,94 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.nio;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * A POIFS {@link DataSource} backed by a byte array.
+ */
+public class ByteArrayBackedDataSource extends DataSource {
+ private byte[] buffer;
+ private long size;
+
+ public ByteArrayBackedDataSource(byte[] data, int size) {
+ this.buffer = data;
+ this.size = size;
+ }
+ public ByteArrayBackedDataSource(byte[] data) {
+ this(data, data.length);
+ }
+
+ public ByteBuffer read(int length, long position) {
+ if(position >= size) {
+ throw new IndexOutOfBoundsException(
+ "Unable to read " + length + " bytes from " +
+ position + " in stream of length " + size
+ );
+ }
+
+ int toRead = (int)Math.min(length, size - position);
+ return ByteBuffer.wrap(buffer, (int)position, toRead);
+ }
+
+ public void write(ByteBuffer src, long position) {
+ // Extend if needed
+ long endPosition = position + src.capacity();
+ if(endPosition > buffer.length) {
+ extend(endPosition);
+ }
+
+ // Now copy
+ src.get(buffer, (int)position, src.capacity());
+
+ // Update size if needed
+ if(endPosition > size) {
+ size = endPosition;
+ }
+ }
+
+ private void extend(long length) {
+ // Consider extending by a bit more than requested
+ long difference = length - buffer.length;
+ if(difference < buffer.length*0.25) {
+ difference = (long)(buffer.length*0.25);
+ }
+ if(difference < 4096) {
+ difference = 4096;
+ }
+
+ byte[] nb = new byte[(int)(difference+buffer.length)];
+ System.arraycopy(buffer, 0, nb, 0, (int)size);
+ buffer = nb;
+ }
+
+ public void copyTo(OutputStream stream) throws IOException {
+ stream.write(buffer, 0, (int)size);
+ }
+
+ public long size() {
+ return size;
+ }
+
+ public void close() {
+ buffer = null;
+ size = -1;
+ }
+}
Added: poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/DataSource.java
URL: http://svn.apache.org/viewvc/poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/DataSource.java?rev=1053791&view=auto
==============================================================================
--- poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/DataSource.java (added)
+++ poi/branches/NIO_32_BRANCH/src/java/org/apache/poi/poifs/nio/DataSource.java Thu Dec 30 02:35:06 2010
@@ -0,0 +1,35 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.nio;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * Common definition of how we read and write bytes
+ */
+public abstract class DataSource {
+ public abstract ByteBuffer read(int length, long position) throws IOException;
+ public abstract void write(ByteBuffer src, long position) throws IOException;
+ public abstract long size() throws IOException;
+ /** Close the underlying stream */
+ public abstract void close() throws IOException;
+ /** Copies the contents to the specified OutputStream */
+ public abstract void copyTo(OutputStream stream) throws IOException;
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org