1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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")
}
}
|