use lopdf::Document;
fn build_conflicting_objstm_pdf() -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(b"%PDF-1.5\n");
let off_1 = buf.len();
buf.extend_from_slice(b"1 0 obj\n<</Type/Catalog/Pages 3 0 R>>\nendobj\n");
let off_2 = buf.len();
let stale_data = b"3 0 <</Type/Pages/Count 1/Kids[5 0 R]>>";
buf.extend_from_slice(
format!(
"2 0 obj\n<</Type/ObjStm/N 1/First 4/Length {}>>\nstream\n",
stale_data.len()
)
.as_bytes(),
);
buf.extend_from_slice(stale_data);
buf.extend_from_slice(b"\nendstream\nendobj\n");
let off_4 = buf.len();
let correct_data = b"3 0 <</Type/Pages/Count 2/Kids[5 0 R 6 0 R]>>";
buf.extend_from_slice(
format!(
"4 0 obj\n<</Type/ObjStm/N 1/First 4/Length {}>>\nstream\n",
correct_data.len()
)
.as_bytes(),
);
buf.extend_from_slice(correct_data);
buf.extend_from_slice(b"\nendstream\nendobj\n");
let off_5 = buf.len();
buf.extend_from_slice(b"5 0 obj\n<</Type/Page/Parent 3 0 R/MediaBox[0 0 612 792]>>\nendobj\n");
let off_6 = buf.len();
buf.extend_from_slice(b"6 0 obj\n<</Type/Page/Parent 3 0 R/MediaBox[0 0 612 792]>>\nendobj\n");
let off_7 = buf.len();
let mut xref_data = Vec::new();
let offsets = [0u32, off_1 as u32, off_2 as u32, 0, off_4 as u32, off_5 as u32, off_6 as u32, off_7 as u32];
xref_data.extend_from_slice(&[0, 0, 0, 0, 0]);
for &off in &offsets[1..=2] {
xref_data.push(1);
xref_data.push((off >> 16) as u8);
xref_data.push((off >> 8) as u8);
xref_data.push(off as u8);
xref_data.push(0);
}
xref_data.push(2);
xref_data.extend_from_slice(&[0, 0, 4]); xref_data.push(0);
for &off in &offsets[4..=7] {
xref_data.push(1);
xref_data.push((off >> 16) as u8);
xref_data.push((off >> 8) as u8);
xref_data.push(off as u8);
xref_data.push(0);
}
buf.extend_from_slice(
format!(
"7 0 obj\n<</Type/XRef/Size 8/W[1 3 1]/Root 1 0 R/Length {}>>\nstream\n",
xref_data.len()
)
.as_bytes(),
);
buf.extend_from_slice(&xref_data);
buf.extend_from_slice(b"\nendstream\nendobj\n");
buf.extend_from_slice(format!("startxref\n{}\n%%EOF", off_7).as_bytes());
buf
}
#[test]
fn test_conflicting_objstm_uses_xref_container() {
let pdf = build_conflicting_objstm_pdf();
let doc = Document::load_mem(&pdf).unwrap();
assert_eq!(
doc.get_pages().len(),
2,
"Should load 2 pages from ObjStm 4, not 1 from stale ObjStm 2"
);
}