diff --git a/src/java/org/apache/poi/hssf/record/RecordInputStream.java b/src/java/org/apache/poi/hssf/record/RecordInputStream.java
index 03944aae3..f9dd2c76c 100755
--- a/src/java/org/apache/poi/hssf/record/RecordInputStream.java
+++ b/src/java/org/apache/poi/hssf/record/RecordInputStream.java
@@ -18,7 +18,6 @@
package org.apache.poi.hssf.record;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.util.LittleEndian;
@@ -35,20 +34,37 @@ public final class RecordInputStream extends InputStream implements LittleEndian
/** Maximum size of a single record (minus the 4 byte header) without a continue*/
public final static short MAX_RECORD_DATA_SIZE = 8224;
private static final int INVALID_SID_VALUE = -1;
+ /**
+ * When {@link #_currentDataLength} has this value, it means that the previous BIFF record is
+ * finished, the next sid has been properly read, but the data size field has not been read yet.
+ */
private static final int DATA_LEN_NEEDS_TO_BE_READ = -1;
private static final byte[] EMPTY_BYTE_ARRAY = { };
- private final InputStream _in;
- /** {@link LittleEndianInput} facet of field {@link #_in} */
+ /** {@link LittleEndianInput} facet of the wrapped {@link InputStream} */
private final LittleEndianInput _le;
- private int currentSid;
+ /** the record identifier of the BIFF record currently being read */
+ private int _currentSid;
+ /**
+ * Length of the data section of the current BIFF record (always 4 less than the total record size).
+ * When uninitialised, this field is set to {@link #DATA_LEN_NEEDS_TO_BE_READ}.
+ */
private int _currentDataLength;
- private int nextSid;
- private int recordOffset;
- private boolean autoContinue; // TODO - remove this
+ /**
+ * The BIFF record identifier for the next record is read when just as the current record
+ * is finished.
+ * This field is only really valid during the time that ({@link #_currentDataLength} ==
+ * {@link #DATA_LEN_NEEDS_TO_BE_READ}). At most other times its value is not really the
+ * 'sid of the next record'. Wwhile mid-record, this field coincidentally holds the sid
+ * of the current record.
+ */
+ private int _nextSid;
+ /**
+ * index within the data section of the current BIFF record
+ */
+ private int _currentDataOffset;
public RecordInputStream(InputStream in) throws RecordFormatException {
- _in = in;
if (in instanceof LittleEndianInput) {
// accessing directly is an optimisation
_le = (LittleEndianInput) in;
@@ -56,22 +72,20 @@ public final class RecordInputStream extends InputStream implements LittleEndian
// less optimal, but should work OK just the same. Often occurs in junit tests.
_le = new LittleEndianInputStream(in);
}
- try {
- if (_in.available() < LittleEndian.SHORT_SIZE) {
- nextSid = INVALID_SID_VALUE;
- } else {
- nextSid = LittleEndian.readShort(in);
- }
- } catch (IOException ex) {
- throw new RecordFormatException("Error reading bytes", ex);
- }
- _currentDataLength = DATA_LEN_NEEDS_TO_BE_READ;
- autoContinue = true;
+ _nextSid = readNextSid();
+ }
+
+ /**
+ * @returns the number of bytes available in the current BIFF record
+ * @see #remaining()
+ */
+ public int available() {
+ return remaining();
}
public int read() {
checkRecordPosition(LittleEndian.BYTE_SIZE);
- recordOffset += LittleEndian.BYTE_SIZE;
+ _currentDataOffset += LittleEndian.BYTE_SIZE;
return _le.readUByte();
}
public int read(byte[] b, int off, int len) {
@@ -83,14 +97,9 @@ public final class RecordInputStream extends InputStream implements LittleEndian
return limit;
}
- public short getSid() {
- return (short) currentSid;
- }
-
- public short getLength() { // TODO - remove
- return (short) _currentDataLength;
- }
-
+ public short getSid() {
+ return (short) _currentSid;
+ }
/**
* Note - this method is expected to be called only when completed reading the current BIFF record.
@@ -98,18 +107,17 @@ public final class RecordInputStream extends InputStream implements LittleEndian
* discarded
*/
public boolean hasNextRecord() {
- if (_currentDataLength != -1 && _currentDataLength != recordOffset) {
- System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(currentSid));
+ if (_currentDataLength != -1 && _currentDataLength != _currentDataOffset) {
+ System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(_currentSid));
// discard unread data
- while (recordOffset < _currentDataLength) {
+ while (_currentDataOffset < _currentDataLength) {
readByte();
}
}
if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
- nextSid = readNextSid();
- _currentDataLength = DATA_LEN_NEEDS_TO_BE_READ;
+ _nextSid = readNextSid();
}
- return nextSid != INVALID_SID_VALUE;
+ return _nextSid != INVALID_SID_VALUE;
}
/**
@@ -117,12 +125,7 @@ public final class RecordInputStream extends InputStream implements LittleEndian
* @return the sid of the next record or {@link #INVALID_SID_VALUE} if at end of stream
*/
private int readNextSid() {
- int nAvailable;
- try {
- nAvailable = _in.available();
- } catch (IOException e) {
- throw new RecordFormatException("Error checking stream available bytes", e);
- }
+ int nAvailable = _le.available();
if (nAvailable < EOFRecord.ENCODED_SIZE) {
if (nAvailable > 0) {
// some scrap left over?
@@ -135,6 +138,7 @@ public final class RecordInputStream extends InputStream implements LittleEndian
if (result == INVALID_SID_VALUE) {
throw new RecordFormatException("Found invalid sid (" + result + ")");
}
+ _currentDataLength = DATA_LEN_NEEDS_TO_BE_READ;
return result;
}
@@ -143,12 +147,14 @@ public final class RecordInputStream extends InputStream implements LittleEndian
* Note: The auto continue flag is reset to true
*/
public void nextRecord() throws RecordFormatException {
- if (nextSid == INVALID_SID_VALUE) {
+ if (_nextSid == INVALID_SID_VALUE) {
throw new IllegalStateException("EOF - next record not available");
}
- currentSid = nextSid;
- autoContinue = true;
- recordOffset = 0;
+ if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
+ throw new IllegalStateException("Cannot call nextRecord() without checking hasNextRecord() first");
+ }
+ _currentSid = _nextSid;
+ _currentDataOffset = 0;
_currentDataLength = _le.readUShort();
if (_currentDataLength > MAX_RECORD_DATA_SIZE) {
throw new RecordFormatException("The content of an excel record cannot exceed "
@@ -156,19 +162,19 @@ public final class RecordInputStream extends InputStream implements LittleEndian
}
}
- public void setAutoContinue(boolean enable) {
- this.autoContinue = enable;
- }
-
private void checkRecordPosition(int requiredByteCount) {
- if (remaining() < requiredByteCount) {
- if (isContinueNext() && autoContinue) {
- nextRecord();
- } else {
- throw new ArrayIndexOutOfBoundsException();
- }
+ int nAvailable = remaining();
+ if (nAvailable >= requiredByteCount) {
+ // all OK
+ return;
}
+ if (nAvailable == 0 && isContinueNext()) {
+ nextRecord();
+ return;
+ }
+ throw new RecordFormatException("Not enough data (" + nAvailable
+ + ") to read requested (" + requiredByteCount +") bytes");
}
/**
@@ -176,7 +182,7 @@ public final class RecordInputStream extends InputStream implements LittleEndian
*/
public byte readByte() {
checkRecordPosition(LittleEndian.BYTE_SIZE);
- recordOffset += LittleEndian.BYTE_SIZE;
+ _currentDataOffset += LittleEndian.BYTE_SIZE;
return _le.readByte();
}
@@ -185,19 +191,19 @@ public final class RecordInputStream extends InputStream implements LittleEndian
*/
public short readShort() {
checkRecordPosition(LittleEndian.SHORT_SIZE);
- recordOffset += LittleEndian.SHORT_SIZE;
+ _currentDataOffset += LittleEndian.SHORT_SIZE;
return _le.readShort();
}
public int readInt() {
checkRecordPosition(LittleEndian.INT_SIZE);
- recordOffset += LittleEndian.INT_SIZE;
+ _currentDataOffset += LittleEndian.INT_SIZE;
return _le.readInt();
}
public long readLong() {
checkRecordPosition(LittleEndian.LONG_SIZE);
- recordOffset += LittleEndian.LONG_SIZE;
+ _currentDataOffset += LittleEndian.LONG_SIZE;
return _le.readLong();
}
@@ -214,13 +220,13 @@ public final class RecordInputStream extends InputStream implements LittleEndian
*/
public int readUShort() {
checkRecordPosition(LittleEndian.SHORT_SIZE);
- recordOffset += LittleEndian.SHORT_SIZE;
+ _currentDataOffset += LittleEndian.SHORT_SIZE;
return _le.readUShort();
}
public double readDouble() {
checkRecordPosition(LittleEndian.DOUBLE_SIZE);
- recordOffset += LittleEndian.DOUBLE_SIZE;
+ _currentDataOffset += LittleEndian.DOUBLE_SIZE;
long valueLongBits = _le.readLong();
double result = Double.longBitsToDouble(valueLongBits);
if (Double.isNaN(result)) {
@@ -235,7 +241,7 @@ public final class RecordInputStream extends InputStream implements LittleEndian
public void readFully(byte[] buf, int off, int len) {
checkRecordPosition(len);
_le.readFully(buf, off, len);
- recordOffset+=len;
+ _currentDataOffset+=len;
}
public String readString() {
@@ -369,20 +375,25 @@ public final class RecordInputStream extends InputStream implements LittleEndian
// already read sid of next record. so current one is finished
return 0;
}
- return (_currentDataLength - recordOffset);
+ return _currentDataLength - _currentDataOffset;
}
/**
*
* @return true
when a {@link ContinueRecord} is next.
*/
- public boolean isContinueNext() {
- if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ && recordOffset != _currentDataLength) {
+ private boolean isContinueNext() {
+ if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ && _currentDataOffset != _currentDataLength) {
throw new IllegalStateException("Should never be called before end of current record");
}
if (!hasNextRecord()) {
return false;
}
- return nextSid == ContinueRecord.sid;
+ // At what point are records continued?
+ // - Often from within the char data of long strings (caller is within readStringCommon()).
+ // - From UnicodeString construction (many different points - call via checkRecordPosition)
+ // - During TextObjectRecord construction (just before the text, perhaps within the text,
+ // and before the formatting run data)
+ return _nextSid == ContinueRecord.sid;
}
}
diff --git a/src/java/org/apache/poi/hssf/record/SupBookRecord.java b/src/java/org/apache/poi/hssf/record/SupBookRecord.java
index 30e337e2d..78d77c5cb 100644
--- a/src/java/org/apache/poi/hssf/record/SupBookRecord.java
+++ b/src/java/org/apache/poi/hssf/record/SupBookRecord.java
@@ -84,9 +84,11 @@ public final class SupBookRecord extends Record {
* @param offset of the record's data (provided a big array of the file)
*/
public SupBookRecord(RecordInputStream in) {
+ int recLen = in.remaining();
+
field_1_number_of_sheets = in.readShort();
- if(in.getLength() > SMALL_RECORD_SIZE) {
+ if(recLen > SMALL_RECORD_SIZE) {
// 5.38.1 External References
_isAddInFunctions = false;
diff --git a/src/java/org/apache/poi/hssf/record/TextObjectRecord.java b/src/java/org/apache/poi/hssf/record/TextObjectRecord.java
index 91780ee44..4bb065e91 100644
--- a/src/java/org/apache/poi/hssf/record/TextObjectRecord.java
+++ b/src/java/org/apache/poi/hssf/record/TextObjectRecord.java
@@ -131,13 +131,7 @@ public final class TextObjectRecord extends Record {
_text = new HSSFRichTextString(text);
if (field_7_formattingDataLength > 0) {
- if (in.isContinueNext() && in.remaining() == 0) {
- in.nextRecord();
- processFontRuns(in, _text, field_7_formattingDataLength);
- } else {
- throw new RecordFormatException(
- "Expected Continue Record to hold font runs for TextObjectRecord");
- }
+ processFontRuns(in, _text, field_7_formattingDataLength);
}
}
@@ -156,10 +150,6 @@ public final class TextObjectRecord extends Record {
throw new RecordFormatException("Bad format run data length " + formattingRunDataLength
+ ")");
}
- if (in.remaining() != formattingRunDataLength) {
- throw new RecordFormatException("Expected " + formattingRunDataLength
- + " bytes but got " + in.remaining());
- }
int nRuns = formattingRunDataLength / FORMAT_RUN_ENCODED_SIZE;
for (int i = 0; i < nRuns; i++) {
short index = in.readShort();
diff --git a/src/java/org/apache/poi/hssf/record/UnicodeString.java b/src/java/org/apache/poi/hssf/record/UnicodeString.java
index 4258d0a6d..0494aa98a 100644
--- a/src/java/org/apache/poi/hssf/record/UnicodeString.java
+++ b/src/java/org/apache/poi/hssf/record/UnicodeString.java
@@ -36,13 +36,8 @@ import java.util.Collections;
* @author Andrew C. Oliver
* @author Marc Johnson (mjohnson at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
- * @version 2.0-pre
*/
-
-public class UnicodeString
- implements Comparable
-{
- public final static short sid = 0xFFF;
+public final class UnicodeString implements Comparable {
private short field_1_charCount; // = 0;
private byte field_2_optionflags; // = 0;
private String field_3_string; // = null;
@@ -53,8 +48,8 @@ public class UnicodeString
private static final BitField richText = BitFieldFactory.getInstance(0x8);
public static class FormatRun implements Comparable {
- private short character;
- private short fontIndex;
+ short character;
+ short fontIndex;
public FormatRun(short character, short fontIndex) {
this.character = character;
@@ -102,15 +97,6 @@ public class UnicodeString
setString(str);
}
- /**
- * construct a unicode string record and fill its fields, ID is ignored
- * @param in the RecordInputstream to read the record from
- */
-
- public UnicodeString(RecordInputStream in)
- {
- fillFields(in); // TODO - inline
- }
public int hashCode()
@@ -142,9 +128,9 @@ public class UnicodeString
&& field_3_string.equals(other.field_3_string));
if (!eq) return false;
- //Ok string appears to be equal but now lets compare formatting runs
+ //OK string appears to be equal but now lets compare formatting runs
if ((field_4_format_runs == null) && (other.field_4_format_runs == null))
- //Strings are equal, and there are not formtting runs.
+ //Strings are equal, and there are not formatting runs.
return true;
if (((field_4_format_runs == null) && (other.field_4_format_runs != null)) ||
(field_4_format_runs != null) && (other.field_4_format_runs == null))
@@ -186,10 +172,10 @@ public class UnicodeString
}
/**
+ * construct a unicode string record and fill its fields, ID is ignored
* @param in the RecordInputstream to read the record from
*/
- protected void fillFields(RecordInputStream in)
- {
+ public UnicodeString(RecordInputStream in) {
field_1_charCount = in.readShort();
field_2_optionflags = in.readByte();
@@ -206,35 +192,13 @@ public class UnicodeString
extensionLength = in.readInt();
}
- //Now need to get the string data.
- //Turn off autocontinuation so that we can catch the continue boundary
- in.setAutoContinue(false);
- StringBuffer tmpString = new StringBuffer(field_1_charCount);
- int stringCharCount = field_1_charCount;
boolean isCompressed = ((field_2_optionflags & 1) == 0);
- while (stringCharCount != 0) {
- if (in.remaining() == 0) {
- if (in.isContinueNext()) {
- in.nextRecord();
- //Check if we are now reading, compressed or uncompressed unicode.
- byte optionflags = in.readByte();
- isCompressed = ((optionflags & 1) == 0);
- } else
- throw new RecordFormatException("Expected continue record.");
- }
- if (isCompressed) {
- char ch = (char)in.readUByte(); // avoid sex
- tmpString.append(ch);
- } else {
- char ch = (char) in.readShort();
- tmpString.append(ch);
- }
- stringCharCount --;
+ if (isCompressed) {
+ field_3_string = in.readCompressedUnicode(field_1_charCount);
+ } else {
+ field_3_string = in.readUnicodeLEString(field_1_charCount);
}
- field_3_string = tmpString.toString();
- //Turn back on autocontinuation
- in.setAutoContinue(true);
-
+
if (isRichText() && (runCount > 0)) {
field_4_format_runs = new ArrayList(runCount);
@@ -305,13 +269,8 @@ public class UnicodeString
}
/**
- * get the actual string this contains as a java String object
- *
- *
- * @return String
- *
+ * @return the actual string this contains as a java String object
*/
-
public String getString()
{
return field_3_string;
@@ -341,7 +300,7 @@ public class UnicodeString
}
}
if (useUTF16)
- //Set the uncomressed bit
+ //Set the uncompressed bit
field_2_optionflags = highByte.setByte(field_2_optionflags);
else field_2_optionflags = highByte.clearByte(field_2_optionflags);
}
@@ -392,7 +351,7 @@ public class UnicodeString
//Make sure that we now say that we are a rich string
field_2_optionflags = richText.setByte(field_2_optionflags);
- }
+ }
public Iterator formatIterator() {
if (field_4_format_runs != null)
@@ -497,8 +456,8 @@ public class UnicodeString
LittleEndian.putShort(data, offset, ContinueRecord.sid);
offset+=2;
- //Record the location of the last continue legnth position, but dont write
- //anything there yet (since we dont know what it will be!)
+ //Record the location of the last continue length position, but don't write
+ //anything there yet (since we don't know what it will be!)
stats.lastLengthPos = offset;
offset += 2;
@@ -506,7 +465,7 @@ public class UnicodeString
stats.remainingSize = SSTRecord.MAX_RECORD_SIZE-4;
}
return offset;
- }
+ }
public int serialize(UnicodeRecordStats stats, final int offset, byte [] data)
{
@@ -514,7 +473,6 @@ public class UnicodeString
//Basic string overhead
pos = writeContinueIfRequired(stats, 3, pos, data);
- // byte[] retval = new byte[ 3 + (getString().length() * charsize)];
LittleEndian.putShort(data, pos, getCharCount());
pos += 2;
data[ pos ] = getOptionFlags();
@@ -568,39 +526,39 @@ public class UnicodeString
//Check to see if the offset occurs mid string, if so then we need to add
//the byte to start with that represents the first byte of the continue record.
if (strSize > stats.remainingSize) {
- //Ok the offset occurs half way through the string, that means that
+ //OK the offset occurs half way through the string, that means that
//we need an extra byte after the continue record ie we didnt finish
//writing out the string the 1st time through
//But hang on, how many continue records did we span? What if this is
//a REALLY long string. We need to work this all out.
- int ammountThatCantFit = strSize;
+ int amountThatCantFit = strSize;
int strPos = 0;
- while (ammountThatCantFit > 0) {
- int ammountWritten = Math.min(stats.remainingSize, ammountThatCantFit);
- //Make sure that the ammount that cant fit takes into account
+ while (amountThatCantFit > 0) {
+ int amountWritten = Math.min(stats.remainingSize, amountThatCantFit);
+ //Make sure that the amount that can't fit takes into account
//whether we are writing double byte unicode
if (isUncompressedUnicode()) {
//We have the '-1' here because whether this is the first record or
//subsequent continue records, there is always the case that the
- //number of bytes in a string on doube byte boundaries is actually odd.
- if ( ( (ammountWritten ) % 2) == 1)
- ammountWritten--;
+ //number of bytes in a string on double byte boundaries is actually odd.
+ if ( ( (amountWritten ) % 2) == 1)
+ amountWritten--;
}
- System.arraycopy(strBytes, strPos, data, pos, ammountWritten);
- pos += ammountWritten;
- strPos += ammountWritten;
- stats.recordSize += ammountWritten;
- stats.remainingSize -= ammountWritten;
+ System.arraycopy(strBytes, strPos, data, pos, amountWritten);
+ pos += amountWritten;
+ strPos += amountWritten;
+ stats.recordSize += amountWritten;
+ stats.remainingSize -= amountWritten;
//Ok lets subtract what we can write
- ammountThatCantFit -= ammountWritten;
+ amountThatCantFit -= amountWritten;
//Each iteration of this while loop is another continue record, unless
//everything now fits.
- if (ammountThatCantFit > 0) {
+ if (amountThatCantFit > 0) {
//We know that a continue WILL be requied, but use this common method
- pos = writeContinueIfRequired(stats, ammountThatCantFit, pos, data);
+ pos = writeContinueIfRequired(stats, amountThatCantFit, pos, data);
//The first byte after a continue mid string is the extra byte to
//indicate if this run is compressed or not.
@@ -686,7 +644,7 @@ public class UnicodeString
return highByte.isSet(getOptionFlags());
}
- /** Returns the size of this record, given the ammount of record space
+ /** Returns the size of this record, given the amount of record space
* remaining, it will also include the size of writing a continue record.
*/
@@ -833,13 +791,6 @@ public class UnicodeString
}
}
-
-
- public short getSid()
- {
- return sid;
- }
-
public int compareTo(Object obj)
{
UnicodeString str = ( UnicodeString ) obj;
@@ -877,7 +828,7 @@ public class UnicodeString
}
//Well the format runs are equal as well!, better check the ExtRst data
- //Which by the way we dont know how to decode!
+ //Which by the way we don't know how to decode!
if ((field_5_ext_rst == null) && (str.field_5_ext_rst == null))
return 0;
if ((field_5_ext_rst == null) && (str.field_5_ext_rst != null))
diff --git a/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java b/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
index c0689bde2..ecd110a32 100644
--- a/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
+++ b/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
@@ -89,8 +89,10 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
_currentBlock = getDataInputBlock(0);
}
- public int available() throws IOException {
- dieIfClosed();
+ public int available() {
+ if (_closed) {
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
+ }
return _document_size - _current_offset;
}
@@ -194,7 +196,7 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
private void checkAvaliable(int requestedSize) {
if (_closed) {
- throw new RuntimeException("cannot perform requested operation on a closed stream");
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
}
if (requestedSize > _document_size - _current_offset) {
throw new RuntimeException("Buffer underrun - requested " + requestedSize
diff --git a/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java b/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
index 2729ab773..984db5f8f 100644
--- a/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
+++ b/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
@@ -40,6 +40,9 @@ public final class LittleEndianByteArrayInputStream implements LittleEndianInput
this(buf, 0, buf.length);
}
+ public int available() {
+ return _endIndex - _readIndex;
+ }
private void checkPosition(int i) {
if (i > _endIndex - _readIndex) {
throw new RuntimeException("Buffer overrun");
diff --git a/src/java/org/apache/poi/util/LittleEndianInput.java b/src/java/org/apache/poi/util/LittleEndianInput.java
index 64bbd1862..dafa7eada 100644
--- a/src/java/org/apache/poi/util/LittleEndianInput.java
+++ b/src/java/org/apache/poi/util/LittleEndianInput.java
@@ -21,6 +21,7 @@ package org.apache.poi.util;
* @author Josh Micich
*/
public interface LittleEndianInput {
+ int available();
byte readByte();
int readUByte();
short readShort();
diff --git a/src/java/org/apache/poi/util/LittleEndianInputStream.java b/src/java/org/apache/poi/util/LittleEndianInputStream.java
index 329119bfb..622ee23cd 100644
--- a/src/java/org/apache/poi/util/LittleEndianInputStream.java
+++ b/src/java/org/apache/poi/util/LittleEndianInputStream.java
@@ -22,6 +22,10 @@ import java.io.IOException;
import java.io.InputStream;
/**
+ * Wraps an {@link InputStream} providing {@link LittleEndianInput}