173 lines
5.1 KiB
Java
173 lines
5.1 KiB
Java
|
|
/*
|
||
|
|
* The Broad Institute
|
||
|
|
* SOFTWARE COPYRIGHT NOTICE AGREEMENT
|
||
|
|
* This is copyright (2007-2008) by the Broad Institute/Massachusetts Institute
|
||
|
|
* of Technology. It is licensed to You under the Gnu Public License, Version 2.0
|
||
|
|
* (the "License"); you may not use this file except in compliance with
|
||
|
|
* the License. You may obtain a copy of the License at
|
||
|
|
*
|
||
|
|
* http://www.opensource.org/licenses/gpl-2.0.php
|
||
|
|
*
|
||
|
|
* This software is supplied without any warranty or guaranteed support
|
||
|
|
* whatsoever. Neither the Broad Institute nor MIT can be responsible for its
|
||
|
|
* use, misuse, or functionality.
|
||
|
|
*/
|
||
|
|
package edu.mit.broad.sam.util;
|
||
|
|
|
||
|
|
import java.io.IOException;
|
||
|
|
import java.io.InputStream;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fast replacement for BufferedReader that assumes that bytes can be converted to chars simply by casting.
|
||
|
|
* @author jrobinso
|
||
|
|
*/
|
||
|
|
public class AsciiLineReader implements LineReader {
|
||
|
|
private static final byte LINEFEED = (byte)('\n' & 0xff);
|
||
|
|
private static final byte CARRIAGE_RETURN = (byte)('\r' & 0xff);
|
||
|
|
|
||
|
|
private final InputStream is;
|
||
|
|
private byte[] buffer;
|
||
|
|
private int nextChar;
|
||
|
|
private int nChars;
|
||
|
|
// Allocate this only once, despite the fact that it is essentially a local variable of readLine()
|
||
|
|
private byte[] lineBuffer = new byte[1000];
|
||
|
|
|
||
|
|
private int lineNumber = 0;
|
||
|
|
|
||
|
|
public AsciiLineReader(final InputStream is) {
|
||
|
|
this(is, 512000);
|
||
|
|
}
|
||
|
|
|
||
|
|
public AsciiLineReader(final InputStream is, final int bufferSize) {
|
||
|
|
this.is = is;
|
||
|
|
buffer = new byte[bufferSize];
|
||
|
|
nextChar = nChars = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
public String readLine() {
|
||
|
|
return readLine(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Read a line of text. A line is considered to be terminated by any one
|
||
|
|
* of a line feed ('\n'), a carriage return ('\r'), or a carriage return
|
||
|
|
* followed immediately by a linefeed.
|
||
|
|
*
|
||
|
|
* @param includeTerminators If true, the line-termination characters
|
||
|
|
* are included in the returned string.
|
||
|
|
*
|
||
|
|
* @return A String containing the contents of the line or null if the
|
||
|
|
* end of the stream has been reached
|
||
|
|
*/
|
||
|
|
public String readLine(final boolean includeTerminators){
|
||
|
|
int linePosition = 0;
|
||
|
|
|
||
|
|
while (true)
|
||
|
|
{
|
||
|
|
if (nChars == -1)
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Refill buffer if neccessary
|
||
|
|
if (nextChar == nChars)
|
||
|
|
{
|
||
|
|
fill();
|
||
|
|
if (nextChar == nChars || nChars == -1)
|
||
|
|
{
|
||
|
|
// eof reached. Return the last line, or null if this is a new line
|
||
|
|
if (linePosition > 0)
|
||
|
|
{
|
||
|
|
++lineNumber;
|
||
|
|
return StringUtil.bytesToString(lineBuffer, 0, linePosition);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
final byte b = buffer[nextChar++];
|
||
|
|
if (b == LINEFEED || b == CARRIAGE_RETURN)
|
||
|
|
{
|
||
|
|
|
||
|
|
if (includeTerminators)
|
||
|
|
{
|
||
|
|
lineBuffer[linePosition++] = b;
|
||
|
|
if (b == CARRIAGE_RETURN && peek() == LINEFEED)
|
||
|
|
{
|
||
|
|
lineBuffer[linePosition++] = b;
|
||
|
|
nextChar++; // <= to account for the '\n' we just ate
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if (b == CARRIAGE_RETURN && peek() == LINEFEED)
|
||
|
|
{
|
||
|
|
nextChar++; // <= skip the trailing \n in case of \r\n termination
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
++lineNumber;
|
||
|
|
return StringUtil.bytesToString(lineBuffer, 0, linePosition);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
// Expand line buffer size if neccessary. Reservce at least 2 characters
|
||
|
|
// for potential line-terminators in return string
|
||
|
|
|
||
|
|
if (linePosition > (lineBuffer.length - 3))
|
||
|
|
{
|
||
|
|
final byte[] temp = new byte[lineBuffer.length + 100];
|
||
|
|
System.arraycopy(lineBuffer, 0, temp, 0, lineBuffer.length);
|
||
|
|
lineBuffer = temp;
|
||
|
|
}
|
||
|
|
|
||
|
|
lineBuffer[linePosition++] = b;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public int getLineNumber() {
|
||
|
|
return lineNumber;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Peek ahead one character, filling from the underlying stream if neccessary.
|
||
|
|
*
|
||
|
|
* @return
|
||
|
|
* @throws java.io.IOException
|
||
|
|
*/
|
||
|
|
private byte peek(){
|
||
|
|
// Refill buffer if neccessary
|
||
|
|
if (nextChar == nChars)
|
||
|
|
{
|
||
|
|
fill();
|
||
|
|
if (nextChar == nChars)
|
||
|
|
{
|
||
|
|
// eof reached.
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return buffer[nextChar];
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private void fill() {
|
||
|
|
try {
|
||
|
|
nChars = is.read(buffer);
|
||
|
|
nextChar = 0;
|
||
|
|
} catch (IOException e) {
|
||
|
|
throw new RuntimeIOException(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void close() {
|
||
|
|
try {
|
||
|
|
is.close();
|
||
|
|
} catch (IOException e) {
|
||
|
|
// Ignore exception
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|