1 package frost.io
2
3 uses frost.unsafe.Pointer
4
5 ====================================================================================================
6 A stream of binary or character data which can be read from.
7 ====================================================================================================
8 @abstract
9 class InputStream {
10 ================================================================================================
11 Determines the endianness of the data in this stream when reading multi-byte values. Defaults to
12 `LITTLE_ENDIAN`, but may be freely changed.
13 ================================================================================================
14 var byteOrder := ByteOrder.LITTLE_ENDIAN
15
16 @private
17 class LineIterator : Iterator<String> {
18 def input:InputStream
19 var _next:String?
20
21 init(input:InputStream) {
22 self.input := input
23 readNext()
24 }
25
26 @override
27 function get_done():Bit {
28 return _next == null
29 }
30
31 @override
32 method next():String {
33 assert _next !== null
34 def result := _next
35 readNext()
36 return result
37 }
38
39 method readNext() {
40 _next := input.readLine()
41 }
42 }
43
44 ================================================================================================
45 Reads and returns a single byte. Blocks until at least one byte is available for reading, or
46 returns `null` if the end of the stream has been reached or in the event of an error.
47 ================================================================================================
48 @abstract
49 method read():UInt8?
50
51 ================================================================================================
52 Reads two bytes from this stream, interpreting them as a `UInt16` value. The interpretation of
53 the bytes is determined by the [byteOrder] field.
54 ================================================================================================
55 @extendable
56 method read():UInt16? {
57 def result:Int16 := read()
58 if result !== null {
59 return result.asUInt16
60 }
61 return null
62 }
63
64 ================================================================================================
65 Reads four bytes from this stream, interpreting them as a `UInt32` value. The interpretation of
66 the bytes is determined by the [byteOrder] field.
67 ================================================================================================
68 @extendable
69 method read():UInt32? {
70 def result:Int32 := read()
71 if result !== null {
72 return result.asUInt32
73 }
74 return null
75 }
76
77 ================================================================================================
78 Reads eight bytes from this stream, interpreting them as a `UInt64` value. The interpretation of
79 the bytes is determined by the [byteOrder] field.
80 ================================================================================================
81 @extendable
82 method read():UInt64? {
83 def result:Int64 := read()
84 if result !== null {
85 return result.asUInt64
86 }
87 return null
88 }
89
90 ================================================================================================
91 Reads a single byte from this stream as an `Int8`.
92 ================================================================================================
93 method read():Int8? {
94 def result:UInt8? := read()
95 if result !== null {
96 return result.asInt8
97 }
98 return null
99 }
100
101 ================================================================================================
102 Reads two bytes from this stream, interpreting them as an `Int16` value. The interpretation of
103 the bytes is determined by the [byteOrder] field.
104 ================================================================================================
105 method read():Int16? {
106 def a:UInt8? := read()
107 if a == null {
108 return null
109 }
110 def b:UInt8? := read()
111 if b == null {
112 return null
113 }
114 if byteOrder = ByteOrder.LITTLE_ENDIAN {
115 return (b << 8 + a).asInt16
116 }
117 else {
118 return (a << 8 + b).asInt16
119 }
120 }
121
122 ================================================================================================
123 Reads four bytes from this stream, interpreting them as an `Int32` value. The interpretation of
124 the bytes is determined by the [byteOrder] field.
125 ================================================================================================
126 method read():Int32? {
127 def a:Int16? := read()
128 if a == null {
129 return null
130 }
131 def b:Int16? := read()
132 if b == null {
133 return null
134 }
135 if byteOrder = ByteOrder.LITTLE_ENDIAN {
136 return b << 16 + a
137 }
138 else {
139 return a << 16 + b
140 }
141 }
142
143 ================================================================================================
144 Reads eight bytes from this stream, interpreting them as an `Int64` value. The interpretation of
145 the bytes is determined by the [byteOrder] field.
146 ================================================================================================
147 method read():Int64? {
148 def a:Int32? := read()
149 if a == null {
150 return null
151 }
152 def b:Int32? := read()
153 if b == null {
154 return null
155 }
156 if byteOrder = ByteOrder.LITTLE_ENDIAN {
157 return b.asInt64 << 32 + a
158 }
159 else {
160 return b.asInt64 << 32 + b
161 }
162 }
163
164 ================================================================================================
165 Reads a single byte from this stream as a `Char8`.
166 ================================================================================================
167 method read():Char8? {
168 def result:UInt8? := read()
169 if result !== null {
170 return Char8(result)
171 }
172 return null
173 }
174
175 ================================================================================================
176 Reads up to `max` bytes from this stream into a buffer and returns the number of bytes actually
177 read. Blocks until at least one byte is available for reading, or returns `0` if the end of the
178 stream has been reached or if an error occurs.
179 ================================================================================================
180 @post(@return >= 0)
181 @extendable
182 method read(buffer:Pointer<UInt8>, max:Int):Int {
183 var i := 0
184 while i < max {< max {
185 def next:UInt8? := read()
186 if next == null {
187 break
188 }
189 buffer[i] := next
190 i += 1
191 }
192 return i
193 }
194
195 ================================================================================================
196 As [read(Pointer<UInt8>, Int)], but treats the read bytes as signed.
197 ================================================================================================
198 method read(buffer:Pointer<Int8>, max:Int):Int {
199 return read(buffer->Pointer<UInt8>, max)
200 }
201
202 ================================================================================================
203 As [read(Pointer<UInt8>, Int)], but treats the read bytes as `Char8`s.
204 ================================================================================================
205 method read(buffer:Pointer<Char8>, max:Int):Int {
206 return read(buffer->Pointer<UInt8>, max)
207 }
208
209 ================================================================================================
210 Reads from this stream until the end, returning the data read as a `String`. As streams may
211 contain a very large (or even infinite) amount of data, you should exercise caution when using
212 `readFully`.
213 ================================================================================================
214 @priority(1)
215 method readFully():String {
216 constant BUFFER_SIZE := 2048
217 def result := MutableString()
218 def buffer := Pointer<UInt8>.alloc(BUFFER_SIZE)
219 loop {
220 def count := read(buffer, BUFFER_SIZE)
221 if count <= 0 {
222 break
223 }
224 result.append(buffer->Pointer<Char8>, count)
225 }
226 buffer.destroy()
227 return result.finish()
228 }
229
230 ================================================================================================
231 Reads from this stream until the end, returning the data read as an `Array<UInt8>`. As streams
232 may contain a very large (or even infinite) amount of data, you should exercise caution when
233 using `readFully`.
234 FIXME error
235 ================================================================================================
236 method readFully():Array<UInt8> {
237 constant BUFFER_SIZE := 2048
238 def result := Array<UInt8>()
239 def buffer := Pointer<UInt8>.alloc(BUFFER_SIZE)
240 loop {
241 def count := read(buffer, BUFFER_SIZE)
242 if count <= 0 {
243 break
244 }
245 -- FIXME need a bulk add
246 for i in 0 .. count {
247 result.add(buffer[i])
248 }
249 }
250 buffer.destroy()
251 return result
252 }
253
254 ================================================================================================
255 Reads a single line of text from this stream and returns it as a `String`. Either `"\n"` or
256 `"\r\n"` is accepted as a valid line ending. The line ending is not part of the returned string.
257 Returns `null` if an error occurs while reading.
258 ================================================================================================
259 @unsafeAccess
260 method readLine():String? {
261 def result := MutableString()
262 loop {
263 def c:Char8? := read()
264 if c == null {
265 if result._length = 0 {
266 return null
267 }
268 break
269 }
270 if c = "\n" {
271 if result._length > 0 & result[result.previous(result.end)] = "\r" {
272 result._length -= 1
273 }
274 break
275 }
276 result.append(c)
277 }
278 return result.finish()
279 }
280
281 ================================================================================================
282 Continually reads from this stream, sending all of the data read to an [OutputStream]. Returns
283 the number of bytes transferred when the end of the input is reached (which may be "never" for
284 some `InputStream`s).
285 ================================================================================================
286 method sendTo(out:OutputStream):Maybe<Int> {
287 var total := 0
288 constant BUFFER_SIZE := 2048
289 def buffer := Pointer<UInt8>.alloc(BUFFER_SIZE)
290 loop {
291 def count := read(buffer, BUFFER_SIZE)
292 if count <= 0 {
293 break
294 }
295 total += count
296 def error := out.write(buffer, count)
297 if error !== null {
298 return Maybe<Int>.ERROR(error)
299 }
300 }
301 buffer.destroy()
302 return Maybe<Int>.SUCCESS(total)
303 }
304
305 ================================================================================================
306 Returns an `Iterator` which reads from this string one line at a time. The `Iterator` will
307 report that it is finished either when the end of the stream is reached or an error occurs.
308 ================================================================================================
309 function lines():Iterator<String> {
310 return LineIterator(self)
311 }
312
313 ================================================================================================
314 Closes this `InputStream`. The default implementation does nothing.
315 ================================================================================================
316 @extendable
317 method close():Error? {
318 return null
319 }
320 }