///|
struct PdfClassicXRefEntry {
object_number : Int
offset : Int
generation : Int
in_use : Bool
object_stream : ObjectStreamReference?
} derive(Debug, Eq, ToJson)
///|
fn pdf_xref_malformed_zero_offset_in_use_free(
tokens : ArrayView[BytesView],
) -> Bool {
tokens.length() >= 3 &&
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 {
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 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: pdf_parse_ascii_int_view(line[0:10]),
generation: pdf_parse_ascii_int_view(line[11:16]),
in_use,
object_stream: None,
})
} else {
None
}
}
///|
fn pdf_read_startxref_position(data : BytesView) -> Int raise PdfError {
let search = pdf_startxref_search_view(data)
let start = 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() && !pdf_is_digit_byte(rest[index].to_int()) {
index += 1
}
let digits_start = index
while index < rest.length() && pdf_is_digit_byte(rest[index].to_int()) {
index += 1
}
pdf_parse_ascii_int_view(rest[digits_start:index])
}
///|
fn pdf_xref_token_in_use(token : BytesView) -> Bool raise PdfError {
if token.length() == 0 {
raise XRefEntryExpected
}
match token[0].to_int() {
110 => true
102 => false
_ => raise XRefEntryExpected
}
}
///|
fn pdf_classic_xref_lookup(
xrefs : ArrayView[PdfClassicXRefEntry],
object_number : Int,
) -> PdfClassicXRefEntry? {
for xref in xrefs {
if xref.in_use && xref.object_number == object_number {
break Some(xref)
}
} nobreak {
None
}
}
///|
priv struct PdfClassicXRefIndex {
entries : @hashmap.HashMap[Int, PdfClassicXRefEntry]
}
///|
fn pdf_classic_xref_index(
xrefs : ArrayView[PdfClassicXRefEntry],
) -> PdfClassicXRefIndex {
let entries : @hashmap.HashMap[Int, PdfClassicXRefEntry] = HashMap([])
for xref in xrefs {
if xref.in_use && !entries.contains(xref.object_number) {
entries[xref.object_number] = xref
}
}
{ entries, }
}
///|
fn PdfClassicXRefIndex::lookup(
self : PdfClassicXRefIndex,
object_number : Int,
) -> PdfClassicXRefEntry? {
self.entries.get(object_number)
}
///|
fn pdf_classic_xrefs_add_newer_first_with_seen(
target : Array[PdfClassicXRefEntry],
seen : @core.PdfNumberSet,
entries : ArrayView[PdfClassicXRefEntry],
) -> Unit {
for entry in entries {
if !seen.contains(entry.object_number) {
target.push(entry)
seen.add(entry.object_number)
}
}
}
///|
fn pdf_cursor_read_classic_xref_entries(
cursor : ByteCursor,
) -> Array[PdfClassicXRefEntry] raise PdfError {
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 {
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() == pdf_no_more {
raise TrailerExpected
} else {
let line = cursor.read_line_view()
let tokens = 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 = pdf_parse_ascii_int_view(tokens[0])
ignore(pdf_parse_ascii_int_view(tokens[1]))
} else if tokens.length() == 3 && pdf_xref_marker_token(tokens[0]) {
object_number = pdf_parse_ascii_int_view(tokens[1])
ignore(pdf_parse_ascii_int_view(tokens[2]))
} else if tokens.length() >= 3 {
entries.push({
object_number,
offset: pdf_parse_ascii_int_view(tokens[0]),
generation: if pdf_xref_malformed_zero_offset_in_use_free(tokens) {
0
} else {
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
}