blob: 0f065238eab02ef87f4d15437c18c78ac69ebea9 (
plain) (
tree)
|
|
package java.io
class BufferedReader(in: Reader, sz: Int) extends Reader {
def this(in: Reader) = this(in, 4096)
private[this] var buf = new Array[Char](sz)
/** Last valid value in the buffer (exclusive) */
private[this] var end = 0
/** Next position to read from buffer */
private[this] var pos = 0
private[this] var closed = false
private[this] var validMark = false
override def close(): Unit = {
closed = true
}
override def mark(readAheadLimit: Int): Unit = {
ensureOpen()
val srcBuf = buf
if (buf.size < readAheadLimit)
buf = new Array[Char](readAheadLimit)
// Move data to beginning of buffer
if (pos != 0 || (buf ne srcBuf))
System.arraycopy(srcBuf, pos, buf, 0, end - pos)
// Update internal state
end -= pos
pos = 0
validMark = true
}
override def markSupported(): Boolean = true
override def read(): Int = {
ensureOpen()
if (prepareRead()) {
val res = buf(pos).toInt
pos += 1
res
} else -1
}
override def read(cbuf: Array[Char], off: Int, len: Int): Int = {
ensureOpen()
if (off < 0 || len < 0 || len > cbuf.length - off)
throw new IndexOutOfBoundsException
if (len == 0) 0
else if (prepareRead()) {
val count = Math.min(len, end - pos)
System.arraycopy(this.buf, pos, cbuf, off, count)
pos += count
count
} else -1
}
def readLine(): String = {
ensureOpen()
var res = ""
while (prepareRead() && buf(pos) != '\n' && buf(pos) != '\r') {
res += buf(pos)
pos += 1
}
if (pos >= end) {
// We have reached the end of the stream (prepareRead() returned false)
if (res == "") null
else res
} else {
// Consume terminator
pos += 1
// Check whether we have a \r\n. This may overrun the buffer
// and then push a value back which may unnecessarily invalidate
// the mark. This mimics java behavior
if (buf(pos-1) == '\r' && prepareRead() && buf(pos) == '\n')
pos += 1 // consume '\n'
res
}
}
override def ready(): Boolean = {
ensureOpen()
pos < end || in.ready()
}
override def reset(): Unit = {
ensureOpen()
if (!validMark) throw new IOException("Mark invalid")
pos = 0
}
override def skip(n: Long): Long = {
if (n < 0) throw new IllegalArgumentException("n negative")
else if (pos < end) {
val count = Math.min(n, end - pos).toInt
pos += count
count.toLong
} else {
validMark = false
in.skip(n)
}
}
/** Prepare the buffer for reading. Returns false if EOF */
private def prepareRead(): Boolean =
pos < end || fillBuffer()
/** Tries to fill the buffer. Returns false if EOF */
private def fillBuffer(): Boolean = {
if (validMark && end < buf.length) {
// we may not do a full re-read, since we'll damage the mark.
val read = in.read(buf, end, buf.length - end)
if (read > 0) // protect from adding -1
end += read
read > 0
} else {
// Full re-read
validMark = false
end = in.read(buf)
pos = 0
end > 0
}
}
private def ensureOpen(): Unit = {
if (closed)
throw new IOException("Operation on closed stream")
}
}
|