poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r707945 [3/4] - in /poi/branches/ooxml: ./ src/contrib/src/org/apache/poi/contrib/poibrowser/ src/java/org/apache/poi/hssf/model/ src/java/org/apache/poi/hssf/record/ src/java/org/apache/poi/hssf/record/constant/ src/java/org/apache/poi/hss...
Date Sun, 26 Oct 2008 07:18:19 GMT
Modified: poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java?rev=707945&r1=707944&r2=707945&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java Sun Oct 26 00:18:17 2008
@@ -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,437 +14,314 @@
    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.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.poifs.storage.DataInputBlock;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * This class provides methods to read a DocumentEntry managed by a
- * Filesystem instance.
+ * {@link POIFSFileSystem} instance.
  *
  * @author Marc Johnson (mjohnson at apache dot org)
  */
-
-public class DocumentInputStream
-    extends InputStream
-{
-
-    // 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;
-
-    // buffer used to read one byte at a time
-    private byte[]           _tiny_buffer;
-
-    // returned by read operations if we're at end of document
-    static private final int EOD = -1;
-
-    /**
-     * 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 DocumentInputStream(final DocumentEntry document)
-        throws IOException
-    {
-        _current_offset = 0;
-        _marked_offset  = 0;
-        _document_size  = document.getSize();
-        _closed         = false;
-        _tiny_buffer    = null;
-        if (document instanceof DocumentNode)
-        {
-            _document = (( DocumentNode ) document).getDocument();
-        }
-        else
-        {
-            throw new IOException("Cannot open internal document storage");
-        }
-    }
-
-    /**
-     * Create an InputStream from the specified Document
-     *
-     * @param document the Document to be read
-     *
-     * @exception IOException if the DocumentEntry cannot be opened
-     *            (like, maybe it has been deleted?)
-     */
-
-    public DocumentInputStream(final POIFSDocument document)
-        throws IOException
-    {
-        _current_offset = 0;
-        _marked_offset  = 0;
-        _document_size  = document.getSize();
-        _closed         = false;
-        _tiny_buffer    = null;
-        _document       = document;
-    }
-
-    /**
-     * Returns the number of bytes that can be read (or skipped over)
-     * from this input stream without blocking by the next caller of a
-     * method for this input stream. The next caller might be the same
-     * thread or or another thread.
-     *
-     * @return the number of bytes that can be read from this input
-     *         stream without blocking.
-     *
-     * @exception IOException on error (such as the stream has been
-     *            closed)
-     */
-
-    public int available()
-        throws IOException
-    {
-        dieIfClosed();
-        return _document_size - _current_offset;
-    }
-
-    /**
-     * Closes this input stream and releases any system resources
-     * associated with the stream.
-     *
-     * @exception IOException
-     */
-
-    public void close()
-        throws IOException
-    {
-        _closed = true;
-    }
-
-    /**
-     * Marks the current position in this input stream. A subsequent
-     * call to the reset method repositions this stream at the last
-     * marked position so that subsequent reads re-read the same
-     * bytes.
-     * <p>
-     * The readlimit arguments tells this input stream to allow that
-     * many bytes to be read before the mark position gets
-     * invalidated. This implementation, however, does not care.
-     * <p>
-     * The general contract of mark is that, if the method
-     * markSupported returns true, the stream somehow remembers all
-     * the bytes read after the call to mark and stands ready to
-     * supply those same bytes again if and whenever the method reset
-     * is called. However, the stream is not required to remember any
-     * data at all if more than readlimit bytes are read from the
-     * stream before reset is called. But this stream will.
-     *
-     * @param ignoredReadlimit the maximum limit of bytes that can be
-     *                         read before the mark position becomes
-     *                         invalid. Ignored by this
-     *                         implementation.
-     */
-
-    public void mark(int ignoredReadlimit)
-    {
-        _marked_offset = _current_offset;
-    }
-
-    /**
-     * Tests if this input stream supports the mark and reset methods.
-     *
-     * @return true
-     */
-
-    public boolean markSupported()
-    {
-        return true;
-    }
-
-    /**
-     * Reads the next byte of data from the input stream. The value
-     * byte is returned as an int in the range 0 to 255. If no byte is
-     * available because the end of the stream has been reached, the
-     * value -1 is returned. The definition of this method in
-     * java.io.InputStream allows this method to block, but it won't.
-     *
-     * @return the next byte of data, or -1 if the end of the stream
-     *         is reached.
-     *
-     * @exception IOException
-     */
-
-    public int read()
-        throws IOException
-    {
-        dieIfClosed();
-        if (atEOD())
-        {
-            return EOD;
-        }
-        if (_tiny_buffer == null)
-        {
-            _tiny_buffer = new byte[ 1 ];
-        }
-        _document.read(_tiny_buffer, _current_offset++);
-        return ((int)_tiny_buffer[ 0 ]) & 0x000000FF;
-    }
-
-    /**
-     * Reads some number of bytes from the input stream and stores
-     * them into the buffer array b. The number of bytes actually read
-     * is returned as an integer. The definition of this method in
-     * java.io.InputStream allows this method to block, but it won't.
-     * <p>
-     * If b is null, a NullPointerException is thrown. If the length
-     * of b is zero, then no bytes are read and 0 is returned;
-     * otherwise, there is an attempt to read at least one byte. If no
-     * byte is available because the stream is at end of file, the
-     * value -1 is returned; otherwise, at least one byte is read and
-     * stored into b.
-     * <p>
-     * The first byte read is stored into element b[0], the next one
-     * into b[1], and so on. The number of bytes read is, at most,
-     * equal to the length of b. Let k be the number of bytes actually
-     * read; these bytes will be stored in elements b[0] through
-     * b[k-1], leaving elements b[k] through b[b.length-1] unaffected.
-     * <p>
-     * If the first byte cannot be read for any reason other than end
-     * of file, then an IOException is thrown. In particular, an
-     * IOException is thrown if the input stream has been closed.
-     * <p>
-     * The read(b) method for class InputStream has the same effect as:
-     * <p>
-     * <code>read(b, 0, b.length)</code>
-     *
-     * @param b the buffer into which the data is read.
-     *
-     * @return the total number of bytes read into the buffer, or -1
-     *         if there is no more data because the end of the stream
-     *         has been reached.
-     *
-     * @exception IOException
-     * @exception NullPointerException
-     */
-
-    public int read(final byte [] b)
-        throws IOException, NullPointerException
-    {
-        return read(b, 0, b.length);
-    }
-
-    /**
-     * Reads up to len bytes of data from the input stream into an
-     * array of bytes. An attempt is made to read as many as len
-     * bytes, but a smaller number may be read, possibly zero. The
-     * number of bytes actually read is returned as an integer.
-     * <p>
-     * The definition of this method in java.io.InputStream allows it
-     * to block, but it won't.
-     * <p>
-     * If b is null, a NullPointerException is thrown.
-     * <p>
-     * If off is negative, or len is negative, or off+len is greater
-     * than the length of the array b, then an
-     * IndexOutOfBoundsException is thrown.
-     * <p>
-     * If len is zero, then no bytes are read and 0 is returned;
-     * otherwise, there is an attempt to read at least one byte. If no
-     * byte is available because the stream is at end of file, the
-     * value -1 is returned; otherwise, at least one byte is read and
-     * stored into b.
-     * <p>
-     * The first byte read is stored into element b[off], the next one
-     * into b[off+1], and so on. The number of bytes read is, at most,
-     * equal to len. Let k be the number of bytes actually read; these
-     * bytes will be stored in elements b[off] through b[off+k-1],
-     * leaving elements b[off+k] through b[off+len-1] unaffected.
-     * <p>
-     * In every case, elements b[0] through b[off] and elements
-     * b[off+len] through b[b.length-1] are unaffected.
-     * <p>
-     * If the first byte cannot be read for any reason other than end
-     * of file, then an IOException is thrown. In particular, an
-     * IOException is thrown if the input stream has been closed.
-     *
-     * @param b the buffer into which the data is read.
-     * @param off the start offset in array b at which the data is
-     *            written.
-     * @param len the maximum number of bytes to read.
-     *
-     * @return the total number of bytes read into the buffer, or -1
-     *         if there is no more data because the end of the stream
-     *         has been reached.
-     *
-     * @exception IOException
-     * @exception NullPointerException
-     * @exception IndexOutOfBoundsException
-     */
-
-    public int read(final byte [] b, final int off, final int len)
-        throws IOException, NullPointerException, IndexOutOfBoundsException
-    {
-        dieIfClosed();
-        if (b == null)
-        {
-            throw new NullPointerException("buffer is 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 EOD;
-        }
-        int limit = Math.min(available(), len);
-
-        if ((off == 0) && (limit == b.length))
-        {
-            _document.read(b, _current_offset);
-        }
-        else
-        {
-            byte[] buffer = new byte[ limit ];
-
-            _document.read(buffer, _current_offset);
-            System.arraycopy(buffer, 0, b, off, limit);
-        }
-        _current_offset += limit;
-        return limit;
-    }
-
-    /**
-     * Repositions this stream to the position at the time the mark
-     * method was last called on this input stream.
-     * <p>
-     * The general contract of reset is:
-     * <p>
-     * <ul>
-     *    <li>
-     *        If the method markSupported returns true, then:
-     *        <ul>
-     *            <li>
-     *                If the method mark has not been called since the
-     *                stream was created, or the number of bytes read
-     *                from the stream since mark was last called is
-     *                larger than the argument to mark at that last
-     *                call, then an IOException might be thrown.
-     *            </li>
-     *            <li>
-     *                If such an IOException is not thrown, then the
-     *                stream is reset to a state such that all the
-     *                bytes read since the most recent call to mark
-     *                (or since the start of the file, if mark has not
-     *                been called) will be resupplied to subsequent
-     *                callers of the read method, followed by any
-     *                bytes that otherwise would have been the next
-     *                input data as of the time of the call to reset.
-     *             </li>
-     *         </ul>
-     *     </li>
-     *     <li>
-     *         If the method markSupported returns false, then:
-     *         <ul>
-     *             <li>
-     *                 The call to reset may throw an IOException.
-     *             </li>
-     *             <li>
-     *                 If an IOException is not thrown, then the
-     *                 stream is reset to a fixed state that depends
-     *                 on the particular type of the input and how it
-     *                 was created. The bytes that will be supplied to
-     *                 subsequent callers of the read method depend on
-     *                 the particular type of the input stream.
-     *             </li>
-     *         </ul>
-     *     </li>
-     * </ul>
-     * <p>
-     * All well and good ... this class's markSupported method returns
-     * true and this method does not care whether you've called mark
-     * at all, or whether you've exceeded the number of bytes
-     * specified in the last call to mark. We're basically walking a
-     * byte array ... mark and reset to your heart's content.
-     */
-
-    public void reset()
-    {
-        _current_offset = _marked_offset;
-    }
-
-    /**
-     * Skips over and discards n bytes of data from this input
-     * stream. The skip method may, for a variety of reasons, end up
-     * skipping over some smaller number of bytes, possibly 0. This
-     * may result from any of a number of conditions; reaching end of
-     * file before n bytes have been skipped is only one
-     * possibility. The actual number of bytes skipped is returned. If
-     * n is negative, no bytes are skipped.
-     *
-     * @param n the number of bytes to be skipped.
-     *
-     * @return the actual number of bytes skipped.
-     *
-     * @exception IOException
-     */
-
-    public long skip(final 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;
-        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;
-    }
-}   // end public class DocumentInputStream
-
+public final class DocumentInputStream extends InputStream implements LittleEndianInput {
+	/** returned by read operations if we're at end of document */
+	private static final int EOF = -1;
+
+	private static final int SIZE_SHORT = 2;
+	private static final int SIZE_INT = 4;
+	private static final int SIZE_LONG = 8;
+
+	/** 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 DocumentInputStream(DocumentEntry document) throws IOException {
+		if (!(document instanceof DocumentNode)) {
+			throw new IOException("Cannot open internal document storage");
+		}
+		_current_offset = 0;
+		_marked_offset = 0;
+		_document_size = document.getSize();
+		_closed = false;
+		_document = ((DocumentNode) document).getDocument();
+		_currentBlock = getDataInputBlock(0);
+	}
+
+	/**
+	 * Create an InputStream from the specified Document
+	 * 
+	 * @param document the Document to be read
+	 */
+	public DocumentInputStream(POIFSDocument document) {
+		_current_offset = 0;
+		_marked_offset = 0;
+		_document_size = document.getSize();
+		_closed = false;
+		_document = document;
+		_currentBlock = getDataInputBlock(0);
+	}
+
+	public int available() {
+		if (_closed) {
+			throw new IllegalStateException("cannot perform requested operation on a closed stream");
+		}
+		return _document_size - _current_offset;
+	}
+
+	public void close() {
+		_closed = true;
+	}
+
+	public void mark(int ignoredReadlimit) {
+		_marked_offset = _current_offset;
+	}
+
+	/**
+	 * Tests if this input stream supports the mark and reset methods.
+	 * 
+	 * @return <code>true</code> always
+	 */
+	public boolean markSupported() {
+		return true;
+	}
+
+	private DataInputBlock getDataInputBlock(int offset) {
+		return _document.getDataInputBlock(offset);
+	}
+
+	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;
+	}
+
+	public int read(byte[] b) throws IOException {
+		return read(b, 0, b.length);
+	}
+
+	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.
+	 */
+	public void reset() {
+		_current_offset = _marked_offset;
+		_currentBlock = getDataInputBlock(_current_offset);
+	}
+
+	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");
+		}
+	}
+
+	public byte readByte() {
+		return (byte) readUByte();
+	}
+
+	public double readDouble() {
+		return Double.longBitsToDouble(readLong());
+	}
+
+	public void readFully(byte[] buf) {
+		readFully(buf, 0, buf.length);
+	}
+
+	public short readShort() {
+		return (short) readUShort();
+	}
+
+	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();
+			}
+		}
+	}
+
+	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;
+	}
+
+	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;
+	}
+
+	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;
+	}
+
+	public int readUByte() {
+		checkAvaliable(1);
+		int result = _currentBlock.readUByte();
+		_current_offset++;
+		if (_currentBlock.available() < 1) {
+			_currentBlock = getDataInputBlock(_current_offset);
+		}
+		return result;
+	}
+}

Modified: poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java?rev=707945&r1=707944&r2=707945&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java Sun Oct 26 00:18:17 2008
@@ -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,26 @@
    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.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 +43,488 @@
  *
  * @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;
+
+	// 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;
+		_big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
+		_property = new DocumentProperty(name, _size);
+		_small_store = new SmallBlockStore(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;
+		_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+		_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
+	 */
+	public POIFSDocument(String name, ListManagedBlock[] blocks, int length) throws IOException {
+		_size = length;
+		_property = new DocumentProperty(name, _size);
+		_property.setDocument(this);
+		if (Property.isSmall(_size)) {
+			_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+			_small_store = new SmallBlockStore(convertRawBlocksToSmallBlocks(blocks));
+		} else {
+			_big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
+			_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+		}
+	}
+
+	/**
+	 * Constructor
+	 *
+	 * @param name the name of the POIFSDocument
+	 * @param stream the InputStream we read data from
+	 */
+	public POIFSDocument(String name, 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[blocks.size()]);
+
+		_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(EMPTY_SMALL_BLOCK_ARRAY);
+		}
+	}
+
+	/**
+	 * 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, POIFSDocumentPath path, POIFSWriterListener writer) {
+		_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(EMPTY_BIG_BLOCK_ARRAY);
+		} else {
+			_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+			_big_store = new BigBlockStore(path, name, size, 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);
+		} else {
+			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;
+
+		/**
+		 * Constructor
+		 *
+		 * @param blocks blocks to construct the store from
+		 */
+		SmallBlockStore(SmallDocumentBlock[] blocks) {
+			smallBlocks = (SmallDocumentBlock[]) 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(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
+			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(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;
+
+		/**
+		 * Constructor
+		 *
+		 * @param blocks the blocks making up the store
+		 */
+		BigBlockStore(DocumentBlock[] blocks) {
+			bigBlocks = (DocumentBlock[]) blocks.clone();
+			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(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
+			bigBlocks = new DocumentBlock[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 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
+		 */
+		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() {
+
+			if (isValid()) {
+				if (writer == null) {
+					return bigBlocks.length;
+				}
+				return (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
+							/ POIFSConstants.BIG_BLOCK_SIZE;
+			}
+			return 0;
+		}
+	} // end private class BigBlockStore
+}

Modified: poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/DocumentBlock.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/DocumentBlock.java?rev=707945&r1=707944&r2=707945&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/DocumentBlock.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/DocumentBlock.java Sun Oct 26 00:18:17 2008
@@ -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,31 +14,27 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.storage;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-
 import java.util.Arrays;
 
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.IntegerField;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.LittleEndianConsts;
 
 /**
  * A block of document data.
  *
  * @author Marc Johnson (mjohnson at apache dot org)
  */
+public final class DocumentBlock extends BigBlock {
+    private static final int BLOCK_SHIFT = 9;
+    private static final int BLOCK_SIZE = 1 << BLOCK_SHIFT;
+    private static final int BLOCK_MASK = BLOCK_SIZE-1;
 
-public class DocumentBlock
-    extends BigBlock
-{
     private static final byte _default_value = ( byte ) 0xFF;
     private byte[]            _data;
     private int               _bytes_read;
@@ -161,45 +156,10 @@
         return rval;
     }
 
-    /**
-     * read data from an array of DocumentBlocks
-     *
-     * @param blocks the blocks to read from
-     * @param buffer the buffer to write the data into
-     * @param offset the offset into the array of blocks to read from
-     */
-
-    public static void read(final DocumentBlock [] blocks,
-                            final byte [] buffer, final int offset)
-    {
-        int firstBlockIndex  = offset / POIFSConstants.BIG_BLOCK_SIZE;
-        int firstBlockOffset = offset % POIFSConstants.BIG_BLOCK_SIZE;
-        int lastBlockIndex   = (offset + buffer.length - 1)
-                               / POIFSConstants.BIG_BLOCK_SIZE;
-
-        if (firstBlockIndex == lastBlockIndex)
-        {
-            System.arraycopy(blocks[ firstBlockIndex ]._data,
-                             firstBlockOffset, buffer, 0, buffer.length);
-        }
-        else
-        {
-            int buffer_offset = 0;
-
-            System.arraycopy(blocks[ firstBlockIndex ]._data,
-                             firstBlockOffset, buffer, buffer_offset,
-                             POIFSConstants.BIG_BLOCK_SIZE
-                             - firstBlockOffset);
-            buffer_offset += POIFSConstants.BIG_BLOCK_SIZE - firstBlockOffset;
-            for (int j = firstBlockIndex + 1; j < lastBlockIndex; j++)
-            {
-                System.arraycopy(blocks[ j ]._data, 0, buffer, buffer_offset,
-                                 POIFSConstants.BIG_BLOCK_SIZE);
-                buffer_offset += POIFSConstants.BIG_BLOCK_SIZE;
-            }
-            System.arraycopy(blocks[ lastBlockIndex ]._data, 0, buffer,
-                             buffer_offset, buffer.length - buffer_offset);
-        }
+    public static DataInputBlock getDataInputBlock(DocumentBlock[] blocks, int offset) {
+        int firstBlockIndex = offset >> BLOCK_SHIFT;
+        int firstBlockOffset= offset & BLOCK_MASK;
+        return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
     }
 
     /* ********** START extension of BigBlock ********** */

Modified: poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java?rev=707945&r1=707944&r2=707945&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java Sun Oct 26 00:18:17 2008
@@ -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,13 +14,15 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.storage;
 
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import org.apache.poi.poifs.common.POIFSConstants;
 
@@ -31,13 +32,14 @@
  *
  * @author  Marc Johnson (mjohnson at apache dot org)
  */
+public final class SmallDocumentBlock implements BlockWritable, ListManagedBlock {
+    private static final int BLOCK_SHIFT = 6;
 
-public class SmallDocumentBlock
-    implements BlockWritable, ListManagedBlock
-{
     private byte[]            _data;
     private static final byte _default_fill         = ( byte ) 0xff;
-    private static final int  _block_size           = 64;
+    private static final int  _block_size           = 1 << BLOCK_SHIFT;
+    private static final int BLOCK_MASK = _block_size-1;
+
     private static final int  _blocks_per_big_block =
         POIFSConstants.BIG_BLOCK_SIZE / _block_size;
 
@@ -178,46 +180,10 @@
         return sdbs;
     }
 
-    /**
-     * read data from an array of SmallDocumentBlocks
-     *
-     * @param blocks the blocks to read from
-     * @param buffer the buffer to write the data into
-     * @param offset the offset into the array of blocks to read from
-     */
-
-    public static void read(final BlockWritable [] blocks,
-                            final byte [] buffer, final int offset)
-    {
-        int firstBlockIndex  = offset / _block_size;
-        int firstBlockOffset = offset % _block_size;
-        int lastBlockIndex   = (offset + buffer.length - 1) / _block_size;
-
-        if (firstBlockIndex == lastBlockIndex)
-        {
-            System.arraycopy(
-                (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data,
-                firstBlockOffset, buffer, 0, buffer.length);
-        }
-        else
-        {
-            int buffer_offset = 0;
-
-            System.arraycopy(
-                (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data,
-                firstBlockOffset, buffer, buffer_offset,
-                _block_size - firstBlockOffset);
-            buffer_offset += _block_size - firstBlockOffset;
-            for (int j = firstBlockIndex + 1; j < lastBlockIndex; j++)
-            {
-                System.arraycopy((( SmallDocumentBlock ) blocks[ j ])._data,
-                                 0, buffer, buffer_offset, _block_size);
-                buffer_offset += _block_size;
-            }
-            System.arraycopy(
-                (( SmallDocumentBlock ) blocks[ lastBlockIndex ])._data, 0,
-                buffer, buffer_offset, buffer.length - buffer_offset);
-        }
+    public static DataInputBlock getDataInputBlock(SmallDocumentBlock[] blocks, int offset) {
+        int firstBlockIndex = offset >> BLOCK_SHIFT;
+        int firstBlockOffset= offset & BLOCK_MASK;
+        return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
     }
 
     /**

Propchange: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sun Oct 26 00:18:17 2008
@@ -1 +1 @@
-/poi/trunk/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java:703100-706540,706772-707481
+/poi/trunk/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java:703100-706540,706772-707481,707486-707802

Modified: poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndian.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndian.java?rev=707945&r1=707944&r2=707945&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndian.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndian.java Sun Oct 26 00:18:17 2008
@@ -28,13 +28,12 @@
  *@author     Marc Johnson (mjohnson at apache dot org)
  *@author     Andrew Oliver (acoliver at apache dot org)
  */
-public final class LittleEndian implements LittleEndianConsts {
+public class LittleEndian implements LittleEndianConsts {
 
     private LittleEndian() {
-    	// no instances of this class
+        // no instances of this class
     }
 
-
     /**
      *  get a short value from a byte array
      *
@@ -42,9 +41,10 @@
      *@param  offset  a starting offset into the byte array
      *@return         the short (16-bit) value
      */
-
-    public static short getShort(final byte[] data, final int offset) {
-        return (short) getNumber(data, offset, SHORT_SIZE);
+    public static short getShort(byte[] data, int offset) {
+        int b0 = data[offset] & 0xFF;
+        int b1 = data[offset+1] & 0xFF;
+        return (short) ((b1 << 8) + (b0 << 0));
     }
 
 
@@ -55,73 +55,32 @@
      *@param  offset  a starting offset into the byte array
      *@return         the unsigned short (16-bit) value in an integer
      */
-    public static int getUShort(final byte[] data, final int offset) {
-        short num = (short) getNumber(data, offset, SHORT_SIZE);
-        int retNum;
-        if (num < 0) {
-            retNum = (Short.MAX_VALUE + 1) * 2 + num;
-        } else {
-            retNum = num;
-        }
-        return retNum;
-    }
-
-
-    /**
-     *  get a short array from a byte array.
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@param  size    Description of the Parameter
-     *@return         The simpleShortArray value
-     */
-    public static short[] getSimpleShortArray(final byte[] data, final int offset, final int size) {
-        short[] results = new short[size];
-        for (int i = 0; i < size; i++) {
-            results[i] = getShort(data, offset + 2 + (i * 2));
-        }
-        return results;
-    }
-
-
-    /**
-     *  get a short array from a byte array. The short array is assumed to start
-     *  with a word describing the length of the array.
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@return         The shortArray value
-     */
-    public static short[] getShortArray(final byte[] data, final int offset) {
-        int size = (int) getNumber(data, offset, SHORT_SIZE);
-        short[] results = getSimpleShortArray(data, offset, size);
-        return results;
+    public static int getUShort(byte[] data, int offset) {
+        int b0 = data[offset] & 0xFF;
+        int b1 = data[offset+1] & 0xFF;
+        return (b1 << 8) + (b0 << 0);
     }
 
-
     /**
      *  get a short value from the beginning of a byte array
      *
      *@param  data  the byte array
      *@return       the short (16-bit) value
      */
-
-    public static short getShort(final byte[] data) {
+    public static short getShort(byte[] data) {
         return getShort(data, 0);
     }
 
-
     /**
      *  get an unsigned short value from the beginning of a byte array
      *
      *@param  data  the byte array
      *@return       the unsigned short (16-bit) value in an int
      */
-    public static int getUShort(final byte[] data) {
+    public static int getUShort(byte[] data) {
         return getUShort(data, 0);
     }
 
-
     /**
      *  get an int value from a byte array
      *
@@ -129,9 +88,13 @@
      *@param  offset  a starting offset into the byte array
      *@return         the int (32-bit) value
      */
-
-    public static int getInt(final byte[] data, final int offset) {
-        return (int) getNumber(data, offset, INT_SIZE);
+    public static int getInt(byte[] data, int offset) {
+        int i=offset;
+        int b0 = data[i++] & 0xFF;
+        int b1 = data[i++] & 0xFF;
+        int b2 = data[i++] & 0xFF;
+        int b3 = data[i++] & 0xFF;
+        return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
     }
 
 
@@ -139,10 +102,9 @@
      *  get an int value from the beginning of a byte array
      *
      *@param  data  the byte array
-     *@return       the int (32-bit) value
+     *@return the int (32-bit) value
      */
-
-    public static int getInt(final byte[] data) {
+    public static int getInt(byte[] data) {
         return getInt(data, 0);
     }
 
@@ -154,15 +116,9 @@
      *@param  offset  a starting offset into the byte array
      *@return         the unsigned int (32-bit) value in a long
      */
-    public static long getUInt(final byte[] data, final int offset) {
-        int num = (int) getNumber(data, offset, INT_SIZE);
-        long retNum;
-        if (num < 0) {
-            retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
-        } else {
-            retNum = num;
-        }
-        return retNum;
+    public static long getUInt(byte[] data, int offset) {
+        long retNum = getInt(data, offset);
+        return retNum & 0x00FFFFFFFF;
     }
 
     /**
@@ -171,8 +127,8 @@
      *@param  data    the byte array
      *@return         the unsigned int (32-bit) value in a long
      */
-    public static long getUInt(final byte[] data) {
-	return getUInt(data,0);
+    public static long getUInt(byte[] data) {
+        return getUInt(data,0);
     }
 
     /**
@@ -182,24 +138,16 @@
      *@param  offset  a starting offset into the byte array
      *@return         the long (64-bit) value
      */
-
-    public static long getLong(final byte[] data, final int offset) {
-        return getNumber(data, offset, LONG_SIZE);
-    }
-
-
-    /**
-     *  get a long value from the beginning of a byte array
-     *
-     *@param  data  the byte array
-     *@return       the long (64-bit) value
-     */
-
-    public static long getLong(final byte[] data) {
-        return getLong(data, 0);
+    public static long getLong(byte[] data, int offset) {
+        long result = 0;
+		
+		for (int j = offset + LONG_SIZE - 1; j >= offset; j--) {
+		    result <<= 8;
+		    result |= 0xff & data[j];
+		}
+		return result;
     }
 
-
     /**
      *  get a double value from a byte array, reads it in little endian format
      *  then converts the resulting revolting IEEE 754 (curse them) floating
@@ -209,24 +157,10 @@
      *@param  offset  a starting offset into the byte array
      *@return         the double (64-bit) value
      */
-
-    public static double getDouble(final byte[] data, final int offset) {
-        return Double.longBitsToDouble(getNumber(data, offset, DOUBLE_SIZE));
-    }
-
-
-    /**
-     *  get a double value from the beginning of a byte array
-     *
-     *@param  data  the byte array
-     *@return       the double (64-bit) value
-     */
-
-    public static double getDouble(final byte[] data) {
-        return getDouble(data, 0);
+    public static double getDouble(byte[] data, int offset) {
+        return Double.longBitsToDouble(getLong(data, offset));
     }
 
-
     /**
      *  put a short value into a byte array
      *
@@ -234,9 +168,10 @@
      *@param  offset  a starting offset into the byte array
      *@param  value   the short (16-bit) value
      */
-    public static void putShort(final byte[] data, final int offset,
-            final short value) {
-        putNumber(data, offset, value, SHORT_SIZE);
+    public static void putShort(byte[] data, int offset, short value) {
+        int i = offset;
+        data[i++] = (byte)((value >>>  0) & 0xFF);
+        data[i++] = (byte)((value >>>  8) & 0xFF);
     }
 
     /**
@@ -247,7 +182,7 @@
      * Added for consistency with other put~() methods
      */
     public static void putByte(byte[] data, int offset, int value) {
-        putNumber(data, offset, value, LittleEndianConsts.BYTE_SIZE);
+        data[offset] = (byte) value;
     }
 
     /**
@@ -259,10 +194,10 @@
      *
      * @exception ArrayIndexOutOfBoundsException may be thrown
      */
-    public static void putUShort(final byte[] data, final int offset,
-                                final int value)
-    {
-        putNumber(data, offset, value, SHORT_SIZE);
+    public static void putUShort(byte[] data, int offset, int value) {
+        int i = offset;
+        data[i++] = (byte)((value >>>  0) & 0xFF);
+        data[i++] = (byte)((value >>>  8) & 0xFF);
     }
 
     /**
@@ -271,8 +206,7 @@
      *@param  data   the byte array
      *@param  value  the short (16-bit) value
      */
-
-    public static void putShort(final byte[] data, final short value) {
+    public static void putShort(byte[] data, short value) {
         putShort(data, 0, value);
     }
 
@@ -284,10 +218,12 @@
      *@param  offset  a starting offset into the byte array
      *@param  value   the int (32-bit) value
      */
-
-    public static void putInt(final byte[] data, final int offset,
-            final int value) {
-        putNumber(data, offset, value, INT_SIZE);
+    public static void putInt(byte[] data, int offset, int value) {
+        int i = offset;
+        data[i++] = (byte)((value >>>  0) & 0xFF);
+        data[i++] = (byte)((value >>>  8) & 0xFF);
+        data[i++] = (byte)((value >>> 16) & 0xFF);
+        data[i++] = (byte)((value >>> 24) & 0xFF);
     }
 
 
@@ -297,8 +233,7 @@
      *@param  data   the byte array
      *@param  value  the int (32-bit) value
      */
-
-    public static void putInt(final byte[] data, final int value) {
+    public static void putInt(byte[] data, int value) {
         putInt(data, 0, value);
     }
 
@@ -310,22 +245,14 @@
      *@param  offset  a starting offset into the byte array
      *@param  value   the long (64-bit) value
      */
-
-    public static void putLong(final byte[] data, final int offset,
-            final long value) {
-        putNumber(data, offset, value, LONG_SIZE);
-    }
-
-
-    /**
-     *  put a long value into beginning of a byte array
-     *
-     *@param  data   the byte array
-     *@param  value  the long (64-bit) value
-     */
-
-    public static void putLong(final byte[] data, final long value) {
-        putLong(data, 0, value);
+    public static void putLong(byte[] data, int offset, long value) {
+        int limit = LONG_SIZE + offset;
+        long v = value;
+        
+        for (int j = offset; j < limit; j++) {
+            data[j] = (byte) (v & 0xFF);
+            v >>= 8;
+        }
     }
 
 
@@ -336,26 +263,13 @@
      *@param  offset  a starting offset into the byte array
      *@param  value   the double (64-bit) value
      */
-
-    public static void putDouble(final byte[] data, final int offset,
-            final double value) {
+    public static void putDouble(byte[] data, int offset, double value) {
         // Excel likes NaN to be a specific value.
-        if (Double.isNaN(value))
-            putNumber(data, offset, -276939487313920L, DOUBLE_SIZE);
-        else
-            putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE);
-    }
-
-
-    /**
-     *  put a double value into beginning of a byte array
-     *
-     *@param  data   the byte array
-     *@param  value  the double (64-bit) value
-     */
-
-    public static void putDouble(final byte[] data, final double value) {
-        putDouble(data, 0, value);
+        if (Double.isNaN(value)) {
+            putLong(data, offset, -276939487313920L);
+        } else {
+            putLong(data, offset, Double.doubleToLongBits(value));
+        }
     }
 
 
@@ -364,7 +278,6 @@
      *
      *@author     Marc Johnson (mjohnson at apache dot org)
      */
-
     public static final class BufferUnderrunException extends IOException {
 
         BufferUnderrunException() {
@@ -376,79 +289,72 @@
     /**
      *  get a short value from an InputStream
      *
-     *@param  stream                       the InputStream from which the short
-     *      is to be read
+     *@param  stream the InputStream from which the short is to be read
      *@return                              the short (16-bit) value
      *@exception  IOException              will be propagated back to the caller
-     *@exception  BufferUnderrunException  if the stream cannot provide enough
-     *      bytes
+     *@exception  BufferUnderrunException  if the stream cannot provide enough bytes
      */
     public static short readShort(InputStream stream) throws IOException, BufferUnderrunException {
 
-		return (short) readUShort(stream);
-	}
+        return (short) readUShort(stream);
+    }
 
-	public static int readUShort(InputStream stream) throws IOException, BufferUnderrunException {
+    public static int readUShort(InputStream stream) throws IOException, BufferUnderrunException {
 
-		int ch1 = stream.read();
-		int ch2 = stream.read();
-		if ((ch1 | ch2) < 0) {
-			throw new BufferUnderrunException();
-		}
-		return ((ch2 << 8) + (ch1 << 0));
-	}
+        int ch1 = stream.read();
+        int ch2 = stream.read();
+        if ((ch1 | ch2) < 0) {
+            throw new BufferUnderrunException();
+        }
+        return (ch2 << 8) + (ch1 << 0);
+    }
     
 
     /**
      *  get an int value from an InputStream
      *
-     *@param  stream                       the InputStream from which the int is
-     *      to be read
-     *@return                              the int (32-bit) value
-     *@exception  IOException              will be propagated back to the caller
-     *@exception  BufferUnderrunException  if the stream cannot provide enough
-     *      bytes
+     *@param  stream the InputStream from which the int is to be read
+     * @return                              the int (32-bit) value
+     * @exception  IOException              will be propagated back to the caller
+     * @exception  BufferUnderrunException  if the stream cannot provide enough bytes
      */
-    public static int readInt(final InputStream stream)
+    public static int readInt(InputStream stream)
              throws IOException, BufferUnderrunException {
-		int ch1 = stream.read();
-		int ch2 = stream.read();
-		int ch3 = stream.read();
-		int ch4 = stream.read();
-		if ((ch1 | ch2 | ch3 | ch4) < 0) {
-			throw new BufferUnderrunException();
-		}
-		return ((ch4 << 24) + (ch3<<16) + (ch2 << 8) + (ch1 << 0));
+        int ch1 = stream.read();
+        int ch2 = stream.read();
+        int ch3 = stream.read();
+        int ch4 = stream.read();
+        if ((ch1 | ch2 | ch3 | ch4) < 0) {
+            throw new BufferUnderrunException();
+        }
+        return (ch4 << 24) + (ch3<<16) + (ch2 << 8) + (ch1 << 0);
     }
 
 
     /**
      *  get a long value from an InputStream
      *
-     *@param  stream                       the InputStream from which the long
-     *      is to be read
-     *@return                              the long (64-bit) value
-     *@exception  IOException              will be propagated back to the caller
-     *@exception  BufferUnderrunException  if the stream cannot provide enough
-     *      bytes
+     * @param  stream the InputStream from which the long is to be read
+     * @return                              the long (64-bit) value
+     * @exception  IOException              will be propagated back to the caller
+     * @exception  BufferUnderrunException  if the stream cannot provide enough bytes
      */
-
-    public static long readLong(final InputStream stream)
+    public static long readLong(InputStream stream)
              throws IOException, BufferUnderrunException {
-		int ch1 = stream.read();
-		int ch2 = stream.read();
-		int ch3 = stream.read();
-		int ch4 = stream.read();
-		int ch5 = stream.read();
-		int ch6 = stream.read();
-		int ch7 = stream.read();
-		int ch8 = stream.read();
-		if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
-			throw new BufferUnderrunException();
-		}
-		
-		return 
-			((long)ch8 << 56) +
+        int ch1 = stream.read();
+        int ch2 = stream.read();
+        int ch3 = stream.read();
+        int ch4 = stream.read();
+        int ch5 = stream.read();
+        int ch6 = stream.read();
+        int ch7 = stream.read();
+        int ch8 = stream.read();
+        if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
+            throw new BufferUnderrunException();
+        }
+        
+        return 
+            ((long)ch8 << 56) +
             ((long)ch7 << 48) +
             ((long)ch6 << 40) +
             ((long)ch5 << 32) +
@@ -459,113 +365,43 @@
     }
 
     /**
-     *  Gets the number attribute of the LittleEndian class
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@param  size    Description of the Parameter
-     *@return         The number value
-     */
-    private static long getNumber(final byte[] data, final int offset,
-            final int size) {
-        long result = 0;
-
-        for (int j = offset + size - 1; j >= offset; j--) {
-            result <<= 8;
-            result |= 0xff & data[j];
-        }
-        return result;
-    }
-
-
-    /**
-     *  Description of the Method
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@param  value   Description of the Parameter
-     *@param  size    Description of the Parameter
-     */
-    private static void putNumber(final byte[] data, final int offset,
-            final long value, final int size) {
-        int limit = size + offset;
-        long v = value;
-
-        for (int j = offset; j < limit; j++) {
-            data[j] = (byte) (v & 0xFF);
-            v >>= 8;
-        }
-    }
-
-
-    /**
      *  Convert an 'unsigned' byte to an integer. ie, don't carry across the
      *  sign.
      *
-     *@param  b  Description of the Parameter
-     *@return    Description of the Return Value
+     * @param  b  Description of the Parameter
+     * @return    Description of the Return Value
      */
     public static int ubyteToInt(byte b) {
-        return ((b & 0x80) == 0 ? (int) b : (b & (byte) 0x7f) + 0x80);
+        return b & 0xFF;
     }
 
 
     /**
      *  get the unsigned value of a byte.
      *
-     *@param  data    the byte array.
-     *@param  offset  a starting offset into the byte array.
-     *@return         the unsigned value of the byte as a 32 bit integer
+     * @param  data    the byte array.
+     * @param  offset  a starting offset into the byte array.
+     * @return         the unsigned value of the byte as a 32 bit integer
      */
-    public static int getUnsignedByte(final byte[] data, final int offset) {
-        return (int) getNumber(data, offset, BYTE_SIZE);
-    }
-
-
-    /**
-     *  get the unsigned value of a byte.
-     *
-     *@param  data  the byte array
-     *@return       the unsigned value of the byte as a 32 bit integer
-     */
-    public static int getUnsignedByte(final byte[] data) {
-        return getUnsignedByte(data, 0);
+    public static int getUnsignedByte(byte[] data, int offset) {
+        return data[offset] & 0xFF;
     }
 
 
     /**
      *  Copy a portion of a byte array
      *
-     *@param  data                        the original byte array
-     *@param  offset                      Where to start copying from.
-     *@param  size                        Number of bytes to copy.
-     *@return                             The byteArray value
-     *@throws  IndexOutOfBoundsException  - if copying would cause access of
+     * @param  data                        the original byte array
+     * @param  offset                      Where to start copying from.
+     * @param  size                        Number of bytes to copy.
+     * @return                             The byteArray value
+     * @throws  IndexOutOfBoundsException  - if copying would cause access of
      *      data outside array bounds.
      */
-    public static byte[] getByteArray(final byte[] data, int offset, int size) {
+    public static byte[] getByteArray(byte[] data, int offset, int size) {
         byte[] copy = new byte[size];
         System.arraycopy(data, offset, copy, 0, size);
 
         return copy;
     }
-
-    /**
-     * <p>Gets an unsigned int value (8 bytes) from a byte array.</p>
-     * 
-     * @param data the byte array
-     * @param offset a starting offset into the byte array
-     * @return the unsigned int (32-bit) value in a long
-     */
-    public static long getULong(final byte[] data, final int offset)
-    {
-        int num = (int) getNumber(data, offset, LONG_SIZE);
-        long retNum;
-        if (num < 0)
-            retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
-        else
-            retNum = num;
-        return retNum;
-    }
-
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndianInput.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndianInput.java?rev=707945&r1=707944&r2=707945&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndianInput.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/util/LittleEndianInput.java Sun Oct 26 00:18:17 2008
@@ -21,6 +21,7 @@
  * @author Josh Micich
  */
 public interface LittleEndianInput {
+	int available();
 	byte readByte();
 	int readUByte();
 	short readShort();
@@ -30,6 +31,4 @@
 	double readDouble();
 	void readFully(byte[] buf);
 	void readFully(byte[] buf, int off, int len);
-	String readUnicodeLEString(int nChars);
-	String readCompressedUnicode(int nChars);
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org


Mime
View raw message