mirror of
https://github.com/apache/poi.git
synced 2025-03-06 17:09:08 +00:00
Buffered LittleEndianInputStream
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1840955 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
24f14e2494
commit
33a4b2f3fb
@ -527,20 +527,16 @@ public final class BiffViewer {
|
||||
}
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (b == null || off < 0 || len < 0 || b.length < off+len) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (_currentPos >= _currentSize) {
|
||||
fillNextBuffer();
|
||||
}
|
||||
if (_currentPos >= _currentSize) {
|
||||
return -1;
|
||||
}
|
||||
int availSize = _currentSize - _currentPos;
|
||||
int result;
|
||||
if (len > availSize) {
|
||||
System.err.println("Unexpected request to read past end of current biff record");
|
||||
result = availSize;
|
||||
} else {
|
||||
result = len;
|
||||
}
|
||||
final int result = Math.min(len, _currentSize - _currentPos);
|
||||
System.arraycopy(_data, _currentPos, b, off, result);
|
||||
_currentPos += result;
|
||||
_overallStreamPos += result;
|
||||
|
@ -105,8 +105,8 @@ public final class RecordInputStream implements LittleEndianInput {
|
||||
|
||||
private final LittleEndianInput _lei;
|
||||
|
||||
public SimpleHeaderInput(InputStream in) {
|
||||
_lei = getLEI(in);
|
||||
private SimpleHeaderInput(LittleEndianInput lei) {
|
||||
_lei = lei;
|
||||
}
|
||||
@Override
|
||||
public int available() {
|
||||
@ -128,8 +128,12 @@ public final class RecordInputStream implements LittleEndianInput {
|
||||
|
||||
public RecordInputStream(InputStream in, EncryptionInfo key, int initialOffset) throws RecordFormatException {
|
||||
if (key == null) {
|
||||
_dataInput = getLEI(in);
|
||||
_bhi = new SimpleHeaderInput(in);
|
||||
_dataInput = (in instanceof LittleEndianInput)
|
||||
// accessing directly is an optimisation
|
||||
? (LittleEndianInput)in
|
||||
// less optimal, but should work OK just the same. Often occurs in junit tests.
|
||||
: new LittleEndianInputStream(in);
|
||||
_bhi = new SimpleHeaderInput(_dataInput);
|
||||
} else {
|
||||
Biff8DecryptingStream bds = new Biff8DecryptingStream(in, initialOffset, key);
|
||||
_dataInput = bds;
|
||||
@ -138,15 +142,6 @@ public final class RecordInputStream implements LittleEndianInput {
|
||||
_nextSid = readNextSid();
|
||||
}
|
||||
|
||||
static LittleEndianInput getLEI(InputStream is) {
|
||||
if (is instanceof LittleEndianInput) {
|
||||
// accessing directly is an optimisation
|
||||
return (LittleEndianInput) is;
|
||||
}
|
||||
// less optimal, but should work OK just the same. Often occurs in junit tests.
|
||||
return new LittleEndianInputStream(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of bytes available in the current BIFF record
|
||||
* @see #remaining()
|
||||
@ -194,11 +189,9 @@ public final class RecordInputStream implements LittleEndianInput {
|
||||
private int readNextSid() {
|
||||
int nAvailable = _bhi.available();
|
||||
if (nAvailable < EOFRecord.ENCODED_SIZE) {
|
||||
if (nAvailable > 0) {
|
||||
// some scrap left over?
|
||||
// ex45582-22397.xls has one extra byte after the last record
|
||||
// Excel reads that file OK
|
||||
}
|
||||
// some scrap left over, if nAvailable > 0?
|
||||
// ex45582-22397.xls has one extra byte after the last record
|
||||
// Excel reads that file OK
|
||||
return INVALID_SID_VALUE;
|
||||
}
|
||||
int result = _bhi.readRecordSID();
|
||||
@ -302,17 +295,13 @@ public final class RecordInputStream implements LittleEndianInput {
|
||||
return _dataInput.readUShort();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a double - might return NaN
|
||||
*/
|
||||
@Override
|
||||
public double readDouble() {
|
||||
long valueLongBits = readLong();
|
||||
double result = Double.longBitsToDouble(valueLongBits);
|
||||
if (Double.isNaN(result)) {
|
||||
// YK: Excel doesn't write NaN but instead converts the cell type into {@link CellType#ERROR}.
|
||||
// HSSF prior to version 3.7 had a bug: it could write Double.NaN but could not read such a file back.
|
||||
// This behavior was fixed in POI-3.7.
|
||||
//throw new RuntimeException("Did not expect to read NaN"); // (Because Excel typically doesn't write NaN)
|
||||
}
|
||||
return result;
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
|
||||
public void readPlain(byte[] buf, int off, int len) {
|
||||
@ -329,7 +318,7 @@ public final class RecordInputStream implements LittleEndianInput {
|
||||
readFully(buf, off, len, false);
|
||||
}
|
||||
|
||||
protected void readFully(byte[] buf, int off, int len, boolean isPlain) {
|
||||
private void readFully(byte[] buf, int off, int len, boolean isPlain) {
|
||||
int origLen = len;
|
||||
if (buf == null) {
|
||||
throw new NullPointerException();
|
||||
|
@ -50,6 +50,7 @@ public final class IOUtils {
|
||||
* @param maxOverride The number of bytes that should be possible to be allocated in one step.
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void setByteArrayMaxOverride(int maxOverride) {
|
||||
BYTE_ARRAY_MAX_OVERRIDE = maxOverride;
|
||||
}
|
||||
@ -395,13 +396,35 @@ public final class IOUtils {
|
||||
* @throws IOException If copying the data fails.
|
||||
*/
|
||||
public static long copy(InputStream inp, OutputStream out) throws IOException {
|
||||
return copy(inp, out, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all the data from the given InputStream to the OutputStream. It
|
||||
* leaves both streams open, so you will still need to close them once done.
|
||||
*
|
||||
* @param inp The {@link InputStream} which provides the data
|
||||
* @param out The {@link OutputStream} to write the data to
|
||||
* @param limit limit the copied bytes - use {@code -1} for no limit
|
||||
* @return the amount of bytes copied
|
||||
*
|
||||
* @throws IOException If copying the data fails.
|
||||
*/
|
||||
public static long copy(InputStream inp, OutputStream out, long limit) throws IOException {
|
||||
final byte[] buff = new byte[4096];
|
||||
long totalCount = 0;
|
||||
for (int count; (count = inp.read(buff)) != -1; totalCount += count) {
|
||||
if (count > 0) {
|
||||
out.write(buff, 0, count);
|
||||
int readBytes = -1;
|
||||
do {
|
||||
int todoBytes = (int)((limit < 0) ? buff.length : Math.min(limit-totalCount, buff.length));
|
||||
if (todoBytes > 0) {
|
||||
readBytes = inp.read(buff, 0, todoBytes);
|
||||
if (readBytes > 0) {
|
||||
out.write(buff, 0, readBytes);
|
||||
totalCount += readBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (readBytes >= 0 && (limit == -1 || totalCount < limit));
|
||||
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.poi.util;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -29,12 +30,16 @@ import java.io.InputStream;
|
||||
*/
|
||||
public class LittleEndianInputStream extends FilterInputStream implements LittleEndianInput {
|
||||
|
||||
private static final int BUFFERED_SIZE = 8096;
|
||||
|
||||
private static final int EOF = -1;
|
||||
private int readIndex = 0;
|
||||
private int markIndex = -1;
|
||||
|
||||
public LittleEndianInputStream(InputStream is) {
|
||||
super(is);
|
||||
super(is.markSupported() ? is : new BufferedInputStream(is, BUFFERED_SIZE));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressForbidden("just delegating")
|
||||
public int available() {
|
||||
@ -60,7 +65,18 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
|
||||
}
|
||||
return LittleEndian.getUByte(buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get a float value, reads it in little endian format
|
||||
* then converts the resulting revolting IEEE 754 (curse them) floating
|
||||
* point number to a happy java float
|
||||
*
|
||||
* @return the float (32-bit) value
|
||||
*/
|
||||
public float readFloat() {
|
||||
return Float.intBitsToFloat( readInt() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble() {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
@ -137,14 +153,42 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
|
||||
}
|
||||
}
|
||||
|
||||
//Makes repeated calls to super.read() until length is read or EOF is reached
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int readBytes = super.read(b, off, len);
|
||||
readIndex += readBytes;
|
||||
return readBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
super.mark(readlimit);
|
||||
markIndex = readIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
super.reset();
|
||||
if (markIndex > -1) {
|
||||
readIndex = markIndex;
|
||||
markIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int getReadIndex() {
|
||||
return readIndex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Makes repeated calls to super.read() until length is read or EOF is reached
|
||||
private int _read(byte[] buffer, int offset, int length) throws IOException {
|
||||
//lifted directly from org.apache.commons.io.IOUtils 2.4
|
||||
int remaining = length;
|
||||
while (remaining > 0) {
|
||||
int location = length - remaining;
|
||||
int count = read(buffer, offset + location, remaining);
|
||||
if (EOF == count) { // EOF
|
||||
if (EOF == count) {
|
||||
break;
|
||||
}
|
||||
remaining -= count;
|
||||
@ -157,4 +201,9 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
|
||||
public void readPlain(byte[] buf, int off, int len) {
|
||||
readFully(buf, off, len);
|
||||
}
|
||||
|
||||
|
||||
public void skipFully(int len) throws IOException {
|
||||
IOUtils.skipFully(this, len);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user