///|
priv struct Reader {
data : Bytes
mut pos : Int32
end : Int32
}
///|
fn Reader::need(self : Reader, n : Int32) -> Unit raise OscError {
if n < 0 || n > self.end - self.pos {
raise Invalid("truncated payload", self.pos)
}
}
///|
fn Reader::word(self : Reader) -> UInt32 raise OscError {
self.need(4)
let p = self.pos
self.pos += 4
(self.data[p].to_uint() << 24) |
(self.data[p + 1].to_uint() << 16) |
(self.data[p + 2].to_uint() << 8) |
self.data[p + 3].to_uint()
}
///|
fn Reader::wide(self : Reader) -> UInt64 raise OscError {
let hi = self.word().to_uint64()
let lo = self.word().to_uint64()
(hi << 32) | lo
}
///|
fn Reader::padding(self : Reader, size : Int32) -> Unit raise OscError {
let n = (4 - size % 4) % 4
self.need(n)
for _ in 0.. String raise OscError {
let start = self.pos
let chars : Array[Char] = []
while true {
self.need(1)
let b = self.data[self.pos].to_int()
self.pos += 1
if b == 0 {
break
}
if b > 127 {
raise Invalid("non-ASCII OSC string", self.pos - 1)
}
if chars.length() >= limits.string_bytes {
raise Limit("string bytes")
}
chars.push(b.to_char().unwrap())
}
self.padding(self.pos - start)
String::from_array(chars[:])
}
///|
fn Reader::blob(self : Reader, limits : Limits) -> Bytes raise OscError {
let n = self.word().reinterpret_as_int()
if n < 0 {
raise Invalid("negative blob length", self.pos - 4)
}
if n > limits.blob_bytes {
raise Limit("blob bytes")
}
self.need(n)
let out = Bytes::from_array(Array::makei(n, i => self.data[self.pos + i]))
self.pos += n
self.padding(n)
out
}