///|
fn pdf_xref_malformed_zero_offset_in_use_free(
tokens : ArrayView[BytesView],
) -> Bool {
tokens.length() >= 3 &&
@core.pdf_view_equals_ascii(tokens[0], [
48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
]) &&
tokens[2].length() > 0 &&
tokens[2][0].to_int() == 110
}
///|
fn pdf_xref_marker_token(token : BytesView) -> Bool {
@core.pdf_view_equals_ascii(token, [120, 114, 101, 102])
}
///|
fn pdf_xref_fixed_width_digits(
line : BytesView,
start : Int,
end : Int,
) -> Bool {
for i in start.. PdfClassicXRefEntry? raise @core.PdfError {
if line.length() >= 18 &&
pdf_xref_fixed_width_digits(line, 0, 10) &&
pdf_xref_fixed_width_digits(line, 11, 16) {
let in_use = match line[17].to_int() {
110 => true
102 => false
_ => raise XRefEntryExpected
}
Some({
object_number,
offset: @core.pdf_parse_ascii_int_view(line[0:10]),
generation: @core.pdf_parse_ascii_int_view(line[11:16]),
in_use,
object_stream: None,
})
} else {
None
}
}
///|
/// Read the numeric byte offset following the final `startxref` marker.
pub fn pdf_read_startxref_position(
data : BytesView,
) -> Int raise @core.PdfError {
let search = @core.pdf_startxref_search_view(data)
let start = @core.pdf_find_last_ascii(search, [
115, 116, 97, 114, 116, 120, 114, 101, 102,
])
if start < 0 {
raise StartXRefExpected
}
let rest = search[start + 9:]
let mut index = 0
while index < rest.length() && !@core.pdf_is_digit_byte(rest[index].to_int()) {
index += 1
}
let digits_start = index
while index < rest.length() && @core.pdf_is_digit_byte(rest[index].to_int()) {
index += 1
}
@core.pdf_parse_ascii_int_view(rest[digits_start:index])
}
///|
/// Parse the in-use flag token from a classic xref entry.
pub fn pdf_xref_token_in_use(token : BytesView) -> Bool raise @core.PdfError {
if token.length() == 0 {
raise XRefEntryExpected
}
match token[0].to_int() {
110 => true
102 => false
_ => raise XRefEntryExpected
}
}
///|
/// Read classic fixed-width or whitespace-tokenized xref entries.
///
/// The cursor must point at the `xref` marker. Reading stops before the
/// following `trailer` marker.
pub fn pdf_cursor_read_classic_xref_entries(
cursor : @core.ByteCursor,
) -> Array[PdfClassicXRefEntry] raise @core.PdfError {
@syntax.pdf_cursor_drop_whitespace(cursor)
pdf_cursor_consume_ascii(cursor, [120, 114, 101, 102], XRefExpected)
let entries : Array[PdfClassicXRefEntry] = []
let mut object_number = 0
let mut done = false
while !done {
@syntax.pdf_cursor_drop_whitespace(cursor)
let position = cursor.absolute_position()
if @syntax.pdf_cursor_matches_ascii_at(cursor, position, [
116, 114, 97, 105, 108, 101, 114,
]) {
done = true
} else if cursor.peek_byte() == @core.pdf_no_more {
raise TrailerExpected
} else {
let line = cursor.read_line_view()
let tokens = @core.pdf_split_whitespace_tokens(line)
match pdf_xref_fixed_width_entry(line, object_number) {
Some(entry) => {
entries.push(entry)
object_number += 1
}
None =>
if tokens.length() == 1 && pdf_xref_marker_token(tokens[0]) {
()
} else if tokens.length() == 2 {
object_number = @core.pdf_parse_ascii_int_view(tokens[0])
ignore(@core.pdf_parse_ascii_int_view(tokens[1]))
} else if tokens.length() == 3 && pdf_xref_marker_token(tokens[0]) {
object_number = @core.pdf_parse_ascii_int_view(tokens[1])
ignore(@core.pdf_parse_ascii_int_view(tokens[2]))
} else if tokens.length() >= 3 {
entries.push({
object_number,
offset: @core.pdf_parse_ascii_int_view(tokens[0]),
generation: if pdf_xref_malformed_zero_offset_in_use_free(tokens) {
0
} else {
@core.pdf_parse_ascii_int_view(tokens[1])
},
in_use: if pdf_xref_malformed_zero_offset_in_use_free(tokens) {
false
} else {
pdf_xref_token_in_use(tokens[2])
},
object_stream: None,
})
object_number += 1
} else {
raise XRefEntryExpected
}
}
}
}
entries
}