///|
pub let pdf_no_more : Int = -1
///|
pub struct ByteCursor {
data : BytesView
mut position : Int
mut offset : Int
source : String
} derive(Debug, Eq, ToJson)
///|
pub fn byte_cursor_of_bytes(
data : PdfBytes,
source? : String = "bytes",
) -> ByteCursor {
byte_cursor_of_view(data[:], source~)
}
///|
pub fn byte_cursor_of_view(
data : BytesView,
source? : String = "bytes",
) -> ByteCursor {
{ data, position: 0, offset: 0, source }
}
///|
pub fn ByteCursor::source(self : ByteCursor) -> String {
self.source
}
///|
pub fn ByteCursor::input_pdf_error(
self : ByteCursor,
message : String,
) -> String {
message +
" whilst reading file " +
self.source +
" at position " +
self.position().to_string()
}
///|
pub fn ByteCursor::length(self : ByteCursor) -> Int {
self.data.length()
}
///|
pub fn ByteCursor::view(self : ByteCursor) -> BytesView {
self.data
}
///|
pub fn ByteCursor::to_bytes(self : ByteCursor) -> PdfBytes {
self.data.to_owned()
}
///|
pub fn ByteCursor::position(self : ByteCursor) -> Int {
self.position - self.offset
}
///|
pub fn ByteCursor::absolute_position(self : ByteCursor) -> Int {
self.position
}
///|
pub fn ByteCursor::remaining_length(self : ByteCursor) -> Int {
if self.position >= self.data.length() {
0
} else {
self.data.length() - self.position
}
}
///|
pub fn ByteCursor::set_offset(
self : ByteCursor,
offset : Int,
) -> Unit raise PdfError {
if offset < 0 {
raise InvalidCursorPosition(offset)
}
if self.offset == 0 {
self.offset = offset
}
}
///|
pub fn ByteCursor::seek(
self : ByteCursor,
position : Int,
) -> Unit raise PdfError {
let absolute = position + self.offset
if absolute < 0 {
raise InvalidCursorPosition(position)
}
self.position = absolute
}
///|
pub fn ByteCursor::input_byte(self : ByteCursor) -> Int {
let value = if self.position > self.data.length() - 1 {
pdf_no_more
} else {
self.data[self.position].to_int()
}
self.position += 1
value
}
///|
pub fn ByteCursor::read_byte(self : ByteCursor) -> Byte? {
if self.position >= self.data.length() {
None
} else {
let value = self.data[self.position]
self.position += 1
Some(value)
}
}
///|
pub fn ByteCursor::peek_byte(self : ByteCursor) -> Int {
let value = self.input_byte()
self.position -= 1
value
}
///|
pub fn ByteCursor::peek(self : ByteCursor) -> Byte? {
let value = self.peek_byte()
if value == pdf_no_more {
None
} else {
Some(value.to_byte())
}
}
///|
pub fn ByteCursor::peek_view(
self : ByteCursor,
length : Int,
) -> BytesView raise PdfError {
if length < 0 {
raise InvalidReadLength(length)
}
let end = self.position + length
if end > self.data.length() {
raise EndOfInput
}
self.data[self.position:end]
}
///|
pub fn ByteCursor::peek_bytes(
self : ByteCursor,
length : Int,
) -> PdfBytes raise PdfError {
self.peek_view(length).to_owned()
}
///|
pub fn ByteCursor::nudge(self : ByteCursor) -> Unit {
ignore(self.input_byte())
}
///|
pub fn ByteCursor::rewind(self : ByteCursor) -> Unit raise PdfError {
if self.position <= self.offset {
raise InvalidCursorPosition(self.position() - 1)
}
self.position -= 1
}
///|
pub fn ByteCursor::read_byte_back(self : ByteCursor) -> Byte? {
if self.position <= self.offset {
None
} else {
self.position -= 1
if self.position >= self.data.length() {
None
} else {
Some(self.data[self.position])
}
}
}
///|
pub fn ByteCursor::remaining_view(self : ByteCursor) -> BytesView {
if self.position >= self.data.length() {
self.data[self.data.length():]
} else {
self.data[self.position:]
}
}
///|
pub fn ByteCursor::read_view(
self : ByteCursor,
length : Int,
) -> BytesView raise PdfError {
if length < 0 {
raise InvalidReadLength(length)
}
let end = self.position + length
if end > self.data.length() {
raise EndOfInput
}
let view = self.data[self.position:end]
self.position = end
view
}
///|
pub fn ByteCursor::read_view_at(
self : ByteCursor,
position : Int,
length : Int,
) -> BytesView raise PdfError {
self.seek(position)
self.read_view(length)
}
///|
pub fn ByteCursor::read_until_view(
self : ByteCursor,
stop : (Int) -> Bool,
eof_is_delimiter? : Bool = true,
) -> BytesView raise PdfError {
let start = self.position
let mut done = false
while !done {
let value = self.peek_byte()
if value == pdf_no_more {
if eof_is_delimiter {
done = true
} else {
raise EndOfInput
}
} else if stop(value) {
done = true
} else {
self.nudge()
}
}
self.data[start:self.position]
}
///|
pub fn ByteCursor::ignore_until(
self : ByteCursor,
stop : (Int) -> Bool,
eof_is_delimiter? : Bool = true,
) -> Unit raise PdfError {
let mut done = false
while !done {
let value = self.peek_byte()
if value == pdf_no_more {
if eof_is_delimiter {
done = true
} else {
raise EndOfInput
}
} else if stop(value) {
done = true
} else {
self.nudge()
}
}
}
///|
pub fn ByteCursor::read_bytes(
self : ByteCursor,
length : Int,
) -> PdfBytes raise PdfError {
self.read_view(length).to_owned()
}
///|
pub fn ByteCursor::read_remaining_bytes(self : ByteCursor) -> PdfBytes {
let view = self.remaining_view()
self.position = self.data.length()
view.to_owned()
}
///|
pub fn ByteCursor::read_bytes_at(
self : ByteCursor,
position : Int,
length : Int,
) -> PdfBytes raise PdfError {
self.read_view_at(position, length).to_owned()
}
///|
pub fn ByteCursor::read_line_view(
self : ByteCursor,
) -> BytesView raise PdfError {
if self.position >= self.data.length() {
raise EndOfInput
}
let start = self.position
let mut done = false
while !done && self.position < self.data.length() {
let value = self.input_byte()
if value == 0x0A {
done = true
} else if value == 0x0D {
if self.position < self.data.length() &&
self.data[self.position].to_int() == 0x0A {
ignore(self.input_byte())
}
done = true
}
}
self.data[start:self.position]
}
///|
pub fn ByteCursor::read_line(self : ByteCursor) -> PdfBytes raise PdfError {
self.read_line_view().to_owned()
}
///|
pub fn ByteCursor::read_line_views(self : ByteCursor) -> Array[BytesView] {
let lines : Array[BytesView] = []
while self.position < self.data.length() {
lines.push(try! self.read_line_view())
}
lines
}
///|
pub fn ByteCursor::read_lines(self : ByteCursor) -> Array[PdfBytes] {
self.read_line_views().map(view => view.to_owned())
}