///|
fn pdf_coord_name(text : String) -> @core.PdfName {
@core.pdf_name_of_bytes(@ascii.encode(text))
}
///|
fn pdf_coord_is_digit(value : Int) -> Bool {
value >= 48 && value <= 57
}
///|
fn pdf_coord_is_number_start(value : Int) -> Bool {
pdf_coord_is_digit(value) || value == 43 || value == 45 || value == 46
}
///|
fn pdf_coord_is_word_boundary(value : Int) -> Bool {
@core.pdf_is_whitespace_byte(value)
}
///|
fn pdf_coord_is_unit_pair(first : Int, second : Int) -> Bool {
(first == 109 && second == 109) ||
(first == 99 && second == 109) ||
(first == 105 && second == 110) ||
(first == 112 && second == 116)
}
///|
fn pdf_coord_spaced_units_length(bytes : BytesView) -> Int {
let mut length = 0
let mut index = 0
while index < bytes.length() {
if index + 1 < bytes.length() &&
pdf_coord_is_unit_pair(bytes[index].to_int(), bytes[index + 1].to_int()) {
length += 4
index += 2
} else {
length += 1
index += 1
}
}
length
}
///|
fn pdf_coord_space_units(text : String) -> String {
let bytes = @utf8.encode(text)
let output = Array::make(pdf_coord_spaced_units_length(bytes), b'\x00')
let mut index = 0
let mut position = 0
while index < bytes.length() {
if index + 1 < bytes.length() &&
pdf_coord_is_unit_pair(bytes[index].to_int(), bytes[index + 1].to_int()) {
output[position] = b' '
output[position + 1] = bytes[index]
output[position + 2] = bytes[index + 1]
output[position + 3] = b' '
position += 4
index += 2
} else {
output[position] = bytes[index]
position += 1
index += 1
}
}
@utf8.decode_lossy(Bytes::from_array(output))
}
///|
fn pdf_coord_number_end(bytes : BytesView, start : Int) -> Int {
let mut index = start
if index < bytes.length() &&
(bytes[index].to_int() == 43 || bytes[index].to_int() == 45) {
index += 1
}
while index < bytes.length() && pdf_coord_is_digit(bytes[index].to_int()) {
index += 1
}
if index < bytes.length() && bytes[index].to_int() == 46 {
index += 1
while index < bytes.length() && pdf_coord_is_digit(bytes[index].to_int()) {
index += 1
}
}
if index < bytes.length() &&
(bytes[index].to_int() == 69 || bytes[index].to_int() == 101) {
let exponent_start = index
index += 1
if index < bytes.length() &&
(bytes[index].to_int() == 43 || bytes[index].to_int() == 45) {
index += 1
}
let digits_start = index
while index < bytes.length() && pdf_coord_is_digit(bytes[index].to_int()) {
index += 1
}
if index == digits_start {
exponent_start
} else {
index
}
} else {
index
}
}
///|
fn pdf_coord_tokenize(text : String) -> Array[PdfCoordToken] {
let bytes = @utf8.encode(pdf_coord_space_units(text))
let tokens : Array[PdfCoordToken] = Array(capacity=bytes.length())
let mut index = 0
while index < bytes.length() {
let value = bytes[index].to_int()
if @core.pdf_is_whitespace_byte(value) {
index += 1
} else if pdf_coord_is_number_start(value) {
let end = pdf_coord_number_end(bytes, index)
if end > index {
let number_text = @ascii.decode_lossy(bytes[index:end])
let parsed : Result[Double, Error] = try
@string.parse_double(number_text)
catch {
err => Err(err)
} noraise {
value => Ok(value)
}
match parsed {
Ok(number) => {
tokens.push(CoordNumber(number))
index = end
}
Err(_) => {
tokens.push(CoordWord(number_text))
index = end
}
}
} else {
tokens.push(CoordWord(@ascii.decode_lossy(bytes[index:index + 1])))
index += 1
}
} else {
let start = index
while index < bytes.length() &&
!pdf_coord_is_word_boundary(bytes[index].to_int()) {
index += 1
}
tokens.push(CoordWord(@ascii.decode_lossy(bytes[start:index])))
}
}
tokens
}