/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.support.io;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import freenet.support.HexUtil;
/**
* A FilterInputStream which provides readLine().
*/
public class LineReadingInputStream extends FilterInputStream implements LineReader {
public LineReadingInputStream(InputStream in) {
super(in);
}
/**
* Read a \n or \r\n terminated line of UTF-8 or ISO-8859-1.
* @param maxLength The maximum length of a line. If a line is longer than this, we throw IOException rather
* than keeping on reading it forever.
* @param bufferSize The initial size of the read buffer.
* @param utf If true, read as UTF-8, if false, read as ISO-8859-1.
*/
@Override
public String readLine(int maxLength, int bufferSize, boolean utf) throws IOException {
if(maxLength < 1)
return null;
if(maxLength <= bufferSize)
bufferSize = maxLength + 1; // Buffer too big, shrink it (add 1 for the optional \r)
if(!markSupported())
return readLineWithoutMarking(maxLength, bufferSize, utf);
byte[] buf = new byte[Math.max(Math.min(128, maxLength), Math.min(1024, bufferSize))];
int ctr = 0;
mark(maxLength + 2); // in case we have both a \r and a \n
while(true) {
assert(buf.length - ctr > 0);
int x = read(buf, ctr, buf.length - ctr);
if(x < 0) {
if(ctr == 0)
return null;
return new String(buf, 0, ctr, utf ? "UTF-8" : "ISO-8859-1");
}
if(x == 0) {
// Don't busy-loop. Probably a socket closed or something.
// If not, it's not a salavageable situation; either way throw.
throw new EOFException();
}
// REDFLAG this is definitely safe with the above charsets, it may not be safe with some wierd ones.
int end = ctr + x;
for(; ctr < end; ctr++) {
if(buf[ctr] == '\n') {
String toReturn = "";
if(ctr != 0) {
boolean removeCR = (buf[ctr - 1] == '\r');
toReturn = new String(buf, 0, (removeCR ? ctr - 1 : ctr), utf ? "UTF-8" : "ISO-8859-1");
}
reset();
skip(ctr + 1);
return toReturn;
}
if(ctr >= maxLength)
throw new TooLongException("We reached maxLength="+maxLength+ " parsing\n "+HexUtil.bytesToHex(buf, 0, ctr) + "\n" + new String(buf, 0, ctr, utf ? "UTF-8" : "ISO-8859-1"));
}
if((buf.length < maxLength) && (buf.length - ctr < bufferSize)) {
byte[] newBuf = new byte[Math.min(buf.length * 2, maxLength)];
System.arraycopy(buf, 0, newBuf, 0, ctr);
buf = newBuf;
}
}
}
protected String readLineWithoutMarking(int maxLength, int bufferSize, boolean utf) throws IOException {
if(maxLength < bufferSize)
bufferSize = maxLength + 1; // Buffer too big, shrink it (add 1 for the optional \r)
byte[] buf = new byte[Math.max(Math.min(128, maxLength), Math.min(1024, bufferSize))];
int ctr = 0;
while(true) {
int x = read();
if(x == -1) {
if(ctr == 0)
return null;
return new String(buf, 0, ctr, utf ? "UTF-8" : "ISO-8859-1");
}
// REDFLAG this is definitely safe with the above charsets, it may not be safe with some wierd ones.
if(x == '\n') {
if(ctr == 0)
return "";
if(buf[ctr - 1] == '\r')
ctr--;
return new String(buf, 0, ctr, utf ? "UTF-8" : "ISO-8859-1");
}
if(ctr >= maxLength)
throw new TooLongException("We reached maxLength="+maxLength+ " parsing\n "+HexUtil.bytesToHex(buf, 0, ctr) + "\n" + new String(buf, 0, ctr, utf ? "UTF-8" : "ISO-8859-1"));
if(ctr >= buf.length) {
buf = Arrays.copyOf(buf, Math.min(buf.length * 2, maxLength));
}
buf[ctr++] = (byte) x;
}
}
}