diff options
Diffstat (limited to 'examples/scala-js/javalib/src/main/scala/java/io/BufferedReader.scala')
-rw-r--r-- | examples/scala-js/javalib/src/main/scala/java/io/BufferedReader.scala | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/examples/scala-js/javalib/src/main/scala/java/io/BufferedReader.scala b/examples/scala-js/javalib/src/main/scala/java/io/BufferedReader.scala new file mode 100644 index 0000000..0f06523 --- /dev/null +++ b/examples/scala-js/javalib/src/main/scala/java/io/BufferedReader.scala @@ -0,0 +1,145 @@ +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") + } + +} |