///|
/// Result of decoding one SQLite variable-length integer.
pub(all) struct Varint {
value : UInt64
length : Int
} derive(Eq, Debug)
///|
/// A bounded cursor over immutable bytes.
///
/// Every read checks the active range before indexing the input. A reader can
/// be forked into a smaller range, which lets page and cell parsers enforce
/// their own boundaries even when the underlying database buffer is larger.
pub(all) struct BinaryReader {
data : Bytes
start : Int
limit : Int
mut position : Int
context : String
}
///|
pub fn BinaryReader::new(data : Bytes) -> BinaryReader {
{ data, start: 0, limit: data.length(), position: 0, context: "binary input" }
}
///|
pub fn BinaryReader::named(data : Bytes, context : String) -> BinaryReader {
{ data, start: 0, limit: data.length(), position: 0, context }
}
///|
pub fn BinaryReader::range(
data : Bytes,
offset : Int,
length : Int,
context : String,
) -> BinaryReader raise ParseError {
guard offset >= 0 && length >= 0 && offset <= data.length() else {
raise InvalidRange(offset, length, data.length(), context)
}
guard length <= data.length() - offset else {
raise InvalidRange(offset, length, data.length(), context)
}
{ data, start: offset, limit: offset + length, position: offset, context }
}
///|
pub fn BinaryReader::absolute_position(self : BinaryReader) -> Int {
self.position
}
///|
pub fn BinaryReader::relative_position(self : BinaryReader) -> Int {
self.position - self.start
}
///|
pub fn BinaryReader::length(self : BinaryReader) -> Int {
self.limit - self.start
}
///|
pub fn BinaryReader::remaining(self : BinaryReader) -> Int {
self.limit - self.position
}
///|
pub fn BinaryReader::is_empty(self : BinaryReader) -> Bool {
self.position >= self.limit
}
///|
fn BinaryReader::require(
self : BinaryReader,
count : Int,
) -> Unit raise ParseError {
guard count >= 0 else {
raise InvalidRange(self.position, count, self.limit, self.context)
}
guard count <= self.remaining() else {
raise UnexpectedEnd(self.position, count, self.remaining(), self.context)
}
}
///|
pub fn BinaryReader::seek_absolute(
self : BinaryReader,
offset : Int,
) -> Unit raise ParseError {
guard offset >= self.start && offset <= self.limit else {
raise InvalidRange(offset, 0, self.limit, self.context)
}
self.position = offset
}
///|
pub fn BinaryReader::seek_relative(
self : BinaryReader,
offset : Int,
) -> Unit raise ParseError {
self.seek_absolute(self.start + offset)
}
///|
pub fn BinaryReader::skip(
self : BinaryReader,
count : Int,
) -> Unit raise ParseError {
self.require(count)
self.position += count
}
///|
pub fn BinaryReader::peek_u8(self : BinaryReader) -> Byte raise ParseError {
self.require(1)
self.data[self.position]
}
///|
pub fn BinaryReader::read_u8(self : BinaryReader) -> Byte raise ParseError {
let value = self.peek_u8()
self.position += 1
value
}
///|
pub fn BinaryReader::read_u16_be(self : BinaryReader) -> Int raise ParseError {
self.require(2)
let a = self.data[self.position].to_int()
let b = self.data[self.position + 1].to_int()
self.position += 2
(a << 8) | b
}
///|
pub fn BinaryReader::read_u24_be(self : BinaryReader) -> Int raise ParseError {
self.require(3)
let a = self.data[self.position].to_int()
let b = self.data[self.position + 1].to_int()
let c = self.data[self.position + 2].to_int()
self.position += 3
(a << 16) | (b << 8) | c
}
///|
pub fn BinaryReader::read_u32_be(
self : BinaryReader,
) -> UInt64 raise ParseError {
self.require(4)
let a = self.data[self.position].to_uint64()
let b = self.data[self.position + 1].to_uint64()
let c = self.data[self.position + 2].to_uint64()
let d = self.data[self.position + 3].to_uint64()
self.position += 4
(a << 24) | (b << 16) | (c << 8) | d
}
///|
pub fn BinaryReader::read_u32_le(
self : BinaryReader,
) -> UInt64 raise ParseError {
self.require(4)
let a = self.data[self.position].to_uint64()
let b = self.data[self.position + 1].to_uint64()
let c = self.data[self.position + 2].to_uint64()
let d = self.data[self.position + 3].to_uint64()
self.position += 4
a | (b << 8) | (c << 16) | (d << 24)
}
///|
pub fn BinaryReader::read_u64_be(
self : BinaryReader,
) -> UInt64 raise ParseError {
self.require(8)
let mut value = 0UL
let mut count = 0
while count < 8 {
value = (value << 8) | self.read_u8().to_uint64()
count += 1
}
value
}
///|
pub fn BinaryReader::read_i8(self : BinaryReader) -> Int raise ParseError {
let value = self.read_u8().to_int()
if value >= 0x80 {
value - 0x100
} else {
value
}
}
///|
pub fn BinaryReader::read_i16_be(self : BinaryReader) -> Int raise ParseError {
let value = self.read_u16_be()
if value >= 0x8000 {
value - 0x10000
} else {
value
}
}
///|
pub fn BinaryReader::read_i24_be(self : BinaryReader) -> Int raise ParseError {
let value = self.read_u24_be()
if value >= 0x800000 {
value - 0x1000000
} else {
value
}
}
///|
pub fn BinaryReader::read_i32_be(self : BinaryReader) -> Int64 raise ParseError {
let value = self.read_u32_be()
if value >= 0x80000000UL {
value.reinterpret_as_int64() - 0x100000000L
} else {
value.reinterpret_as_int64()
}
}
///|
pub fn BinaryReader::read_i64_be(self : BinaryReader) -> Int64 raise ParseError {
self.read_u64_be().reinterpret_as_int64()
}
///|
pub fn BinaryReader::read_f64_be(
self : BinaryReader,
) -> Double raise ParseError {
self.read_u64_be().reinterpret_as_double()
}
///|
pub fn BinaryReader::read_bytes(
self : BinaryReader,
count : Int,
) -> Bytes raise ParseError {
self.require(count)
let begin = self.position
self.position += count
Bytes::makei(count, fn(index) { self.data[begin + index] })
}
///|
pub fn BinaryReader::read_ascii(
self : BinaryReader,
count : Int,
) -> String raise ParseError {
let bytes = self.read_bytes(count)
let chars : Array[Char] = []
for index = 0; index < bytes.length(); index = index + 1 {
chars.push(bytes[index].to_int().to_char().unwrap())
}
String::from_array(chars)
}
///|
pub fn BinaryReader::fork(
self : BinaryReader,
count : Int,
context : String,
) -> BinaryReader raise ParseError {
self.require(count)
let child = BinaryReader::range(self.data, self.position, count, context)
self.position += count
child
}
///|
/// Decode SQLite's one-to-nine-byte unsigned varint representation.
pub fn BinaryReader::read_varint(
self : BinaryReader,
) -> Varint raise ParseError {
let begin = self.position
let mut value = 0UL
for index = 0; index < 8; index = index + 1 {
let byte = self.read_u8().to_int()
if byte < 0x80 {
value = (value << 7) | byte.to_uint64()
return { value, length: self.position - begin }
}
value = (value << 7) | (byte & 0x7f).to_uint64()
}
let ninth = self.read_u8().to_uint64()
value = (value << 8) | ninth
{ value, length: 9 }
}
///|
/// Decode a varint without changing the reader's position.
pub fn BinaryReader::peek_varint(
self : BinaryReader,
) -> Varint raise ParseError {
let saved = self.position
let value = self.read_varint()
self.position = saved
value
}
///|
/// Read an unsigned big-endian integer using exactly `width` bytes.
pub fn BinaryReader::read_uint_be(
self : BinaryReader,
width : Int,
) -> UInt64 raise ParseError {
guard width >= 0 && width <= 8 else {
raise InvalidValue(self.position, "integer width", width.to_string())
}
self.require(width)
let mut value = 0UL
let mut count = 0
while count < width {
value = (value << 8) | self.read_u8().to_uint64()
count += 1
}
value
}
///|
/// Read a two's-complement signed big-endian integer using 1..8 bytes.
pub fn BinaryReader::read_int_be(
self : BinaryReader,
width : Int,
) -> Int64 raise ParseError {
guard width >= 1 && width <= 8 else {
raise InvalidValue(self.position, "signed integer width", width.to_string())
}
let value = self.read_uint_be(width)
if width == 8 {
return value.reinterpret_as_int64()
}
let bits = width * 8
let sign_bit = 1UL << (bits - 1)
if (value & sign_bit) == 0UL {
value.reinterpret_as_int64()
} else {
value.reinterpret_as_int64() - (1UL << bits).reinterpret_as_int64()
}
}
///|
pub fn bytes_equal(left : Bytes, right : Bytes) -> Bool {
if left.length() != right.length() {
return false
}
for index = 0; index < left.length(); index = index + 1 {
if left[index] != right[index] {
return false
}
}
true
}
///|
pub fn bytes_hex(data : Bytes) -> String {
let digits : Array[Char] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
]
let buffer = StringBuilder::new()
for index = 0; index < data.length(); index = index + 1 {
let value = data[index].to_int()
buffer.write_char(digits[(value >> 4) & 0x0f])
buffer.write_char(digits[value & 0x0f])
}
buffer.to_string()
}