mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 04:12:00 +00:00
M1: the delimiter test rewrites only the cut-off update, and a comment after obj is tested to end the keyword (core.repair-broken-files)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
577842d494
commit
9b470180ab
@@ -9196,13 +9196,33 @@ fn trailing_data_without_objects_reads_as_before() {
|
||||
assert_eq!((count, size, model), (1, (200, 100), 1));
|
||||
}
|
||||
|
||||
/// A cut-off update on `one_page_file` whose object headers are written `N G obj{after}<<` in place
|
||||
/// of `N G obj\n<<`. Only the update is rewritten, so the base file's table stays at the offset
|
||||
/// its `startxref` names and reading it raises no error that would rebuild the file anyway: the
|
||||
/// update is found only if the header scan accepts what follows `obj`.
|
||||
fn cut_off_update_with_headers(after: &str) -> Vec<u8> {
|
||||
let base = one_page_file();
|
||||
let mut file = with_update(&base, 5000, false);
|
||||
let update = String::from_utf8(file.split_off(base.len())).unwrap();
|
||||
assert_eq!(update.matches(" obj\n<<").count(), 3, "every updated header is rewritten");
|
||||
file.extend_from_slice(update.replace(" obj\n<<", &format!(" obj{after}<<")).as_bytes());
|
||||
file
|
||||
}
|
||||
|
||||
/// A cut-off update whose object headers run straight into their dictionaries (`4 0 obj<<`) is
|
||||
/// still found: a delimiter ends the keyword (ISO 32000-2 §7.2.2), and the renderer shows the
|
||||
/// update's new first page.
|
||||
/// still found: a delimiter ends the keyword (ISO 32000-2 §7.2.3, Table 2), and the renderer
|
||||
/// shows the update's new first page.
|
||||
#[test]
|
||||
fn a_cut_off_update_with_obj_followed_by_a_delimiter_is_rebuilt() {
|
||||
let file = String::from_utf8(with_update(&one_page_file(), 5000, false)).unwrap().replace(" obj\n<<", " obj<<").into_bytes();
|
||||
let ((count, size), model) = renderer_and_model_pages(file);
|
||||
let ((count, size), model) = renderer_and_model_pages(cut_off_update_with_headers(""));
|
||||
assert_eq!((count, size, model), (2, (300, 150), 2));
|
||||
}
|
||||
|
||||
/// The same with a comment straight after the keyword (`4 0 obj%comment`): `%` is a delimiter
|
||||
/// that starts a comment (ISO 32000-2 §7.2.3 Table 2, §7.2.4), so it ends the keyword too.
|
||||
#[test]
|
||||
fn a_cut_off_update_with_obj_followed_by_a_comment_is_rebuilt() {
|
||||
let ((count, size), model) = renderer_and_model_pages(cut_off_update_with_headers("%comment\n"));
|
||||
assert_eq!((count, size, model), (2, (300, 150), 2));
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-3
@@ -918,9 +918,9 @@ pub(crate) fn cut_off_update_follows(data: &[u8]) -> bool {
|
||||
/// PdfCraft patch: (hayro-syntax (43)) whether `data` holds an `N G obj` header: two runs of
|
||||
/// digits and the keyword, separated by white space, at the start of the data or after white
|
||||
/// space or `>`, the keyword ended by white space, a delimiter or the end of the data (ISO
|
||||
/// 32000-2 §7.2.2), as the document model's repair scan reads it: `1 0 obj_name` is no header,
|
||||
/// and neither is one whose object number doesn't fit 32 bits (`4294967296 0 obj`), which that
|
||||
/// scan skips too. One linear pass, no allocation.
|
||||
/// 32000-2 §7.2.3, Table 2), as the document model's repair scan reads it: `1 0 obj_name` is
|
||||
/// no header, and neither is one whose object number doesn't fit 32 bits (`4294967296 0 obj`),
|
||||
/// which that scan skips too. One linear pass, no allocation.
|
||||
fn has_object_header(data: &[u8]) -> bool {
|
||||
let digits = |from: usize| {
|
||||
data.get(from..).map_or(0, |rest| {
|
||||
|
||||
Reference in New Issue
Block a user