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  }