//! Generate valid minimal PDF fixtures for document model testing. //! //! FIXTURE PASSWORDS: //! - All encrypted fixtures use user password "test" (NOT secret - these are test fixtures) use std::fs::File; use std::io::Write; fn main() { println!("Generating document-model test fixtures..."); generate_all_fixtures(); println!("\nAll fixtures generated!"); println!("Note: Encrypted fixtures need to be manually encrypted with qpdf or similar tool."); } fn generate_all_fixtures() { create_encrypted_rc4_base(); create_tagged_3_level_outline(); create_ocg_default_off(); create_multi_revision_3(); create_inheritance_grandparent_mediabox(); create_missing_mediabox(); create_partial_resource_override(); create_js_in_openaction(); create_xfa_form(); create_pdfa_1b_conformance(); create_page_labels_roman_arabic(); } /// Create base PDF for RC4 encryption (will be encrypted later with qpdf) fn create_encrypted_rc4_base() { let pdf = minimal_pdf("Hello Encrypted", "Test content for encrypted PDF"); write_pdf("tests/document_model/fixtures/_temp_enc_rc4.pdf", &pdf); println!("Created _temp_enc_rc4.pdf (encrypt with: qpdf --encrypt test '' 2 -- _temp_enc_rc4.pdf encrypted_rc4_test.pdf)"); } /// Create a 3-level outline fixture fn create_tagged_3_level_outline() { let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (Chapter 1) Tj ET endstream endobj 3 0 obj <>stream BT /F1 12 Tf 100 700 Td (Section 1.1) Tj ET endstream endobj 4 0 obj <>stream BT /F1 12 Tf 100 700 Td (Subsection 1.1.1) Tj ET endstream endobj 5 0 obj <>>>> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 13 0 obj <> endobj xref 0 14 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000137 00000 n 0000000216 00000 n 0000000295 00000 n 0000000466 00000 n 0000000569 00000 n 0000000672 00000 n 0000000775 00000 n 0000000890 00000 n 0000001005 00000 n 0000001120 00000 n 0000001219 00000 n trailer <> startxref 1318 %%EOF "# ); write_pdf("tests/document_model/fixtures/tagged_3_level_outline.pdf", &pdf); println!("Created tagged_3_level_outline.pdf (3-level outline hierarchy)"); } /// Create OCG with /BaseState /OFF fn create_ocg_default_off() { let pdf = format!( r#"%PDF-1.5 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (Test) Tj ET endstream endobj 3 0 obj <> endobj 4 0 obj <> endobj 5 0 obj <> endobj 6 0 obj <>>>/Parent 7 0 R>> endobj 7 0 obj <> endobj 8 0 obj <> endobj xref 0 9 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000137 00000 n 0000000196 00000 n 0000000229 00000 n 0000000310 00000 n 0000000469 00000 n 0000000522 00000 n trailer <> startxref 629 %%EOF "# ); write_pdf("tests/document_model/fixtures/ocg_default_off.pdf", &pdf); println!("Created ocg_default_off.pdf (OCG with /BaseState /OFF)"); } /// Create a 3-page PDF for multi-revision testing (base version) fn create_multi_revision_3() { let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (Rev 1) Tj ET endstream endobj 3 0 obj <>stream BT /F1 12 Tf 100 700 Td (Rev 2) Tj ET endstream endobj 4 0 obj <>stream BT /F1 12 Tf 100 700 Td (Rev 3) Tj ET endstream endobj 5 0 obj <>>>> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj xref 0 10 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000135 00000 n 0000000208 00000 n 0000000281 00000 n 0000000452 00000 n 0000000555 00000 n 0000000658 00000 n 0000000761 00000 n trailer <> startxref 864 %%EOF "# ); write_pdf("tests/document_model/fixtures/multi_revision_3.pdf", &pdf); println!("Created multi_revision_3.pdf (base 3-page PDF)"); } /// Create MediaBox inheritance from grandparent /Pages node fn create_inheritance_grandparent_mediabox() { let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (Page 1) Tj ET endstream endobj 3 0 obj <>stream BT /F1 12 Tf 100 700 Td (Page 2) Tj ET endstream endobj 4 0 obj <> endobj 5 0 obj <>>>> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj xref 0 9 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000135 00000 n 0000000208 00000 n 0000000289 00000 n 0000000474 00000 n 0000000569 00000 n 0000000664 00000 n trailer <> startxref 767 %%EOF "# ); write_pdf("tests/document_model/fixtures/inheritance_grandparent_mediabox.pdf", &pdf); println!("Created inheritance_grandparent_mediabox.pdf (MediaBox from grandparent)"); } /// Create PDF with no MediaBox anywhere (should default to US Letter) fn create_missing_mediabox() { let pdf = format!( r#"%PDF-1.4 1 0 obj <>stream BT /F1 12 Tf 100 700 Td (No MediaBox) Tj ET endstream endobj 2 0 obj <>>>> endobj 3 0 obj <>>>> endobj 4 0 obj <> endobj 5 0 obj <> endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000071 00000 n 0000000184 00000 n 0000000297 00000 n 0000000370 00000 n trailer <> startxref 473 %%EOF "# ); write_pdf("tests/document_model/fixtures/missing_mediabox.pdf", &pdf); println!("Created missing_mediabox.pdf (no MediaBox, defaults to US Letter)"); } /// Create partial /Resources override fixture fn create_partial_resource_override() { let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <> endobj 3 0 obj <> endobj 4 0 obj <> endobj 5 0 obj <>stream BT /F1 12 Tf 100 700 Td (Test Override) Tj ET endstream endobj 6 0 obj <>/XObject<>>> endobj 7 0 obj <>>> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj xref 0 11 0000000000 65535 f 0000000009 00000 n 0000000074 00000 n 0000000157 00000 n 0000000240 00000 n 0000000331 00000 n 0000000412 00000 n 0000000513 00000 n 0000000586 00000 n 0000000729 00000 n 0000000802 00000 n trailer <> startxref 899 %%EOF "# ); write_pdf("tests/document_model/fixtures/partial_resource_override.pdf", &pdf); println!("Created partial_resource_override.pdf (partial /Resources override)"); } /// Create PDF with /OpenAction /S /JavaScript fn create_js_in_openaction() { let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (JS Test) Tj ET endstream endobj 3 0 obj <> endobj 4 0 obj <>>>/Parent 5 0 R>> endobj 5 0 obj <> endobj 6 0 obj <> endobj xref 0 7 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000135 00000 n 0000000246 00000 n 0000000425 00000 n 0000000478 00000 n trailer <> startxref 551 %%EOF "# ); write_pdf("tests/document_model/fixtures/js_in_openaction.pdf", &pdf); println!("Created js_in_openaction.pdf (/OpenAction /S /JavaScript)"); } /// Create PDF with /AcroForm /XFA fn create_xfa_form() { let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (XFA) Tj ET endstream endobj 3 0 obj <> endobj 4 0 obj <>>>/Parent 5 0 R>> endobj 5 0 obj <> endobj 6 0 obj <> endobj xref 0 7 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000127 00000 n 0000000182 00000 n 0000000353 00000 n 0000000406 00000 n trailer <> startxref 479 %%EOF "# ); write_pdf("tests/document_model/fixtures/xfa_form.pdf", &pdf); println!("Created xfa_form.pdf (/AcroForm /XFA present)"); } /// Create PDF/A-1B conformance with XMP metadata fn create_pdfa_1b_conformance() { let xmp = r#" 1 B "#; let xmp_bytes = xmp.as_bytes(); let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (PDF/A-1B) Tj ET endstream endobj 3 0 obj <> stream {} endstream endobj 4 0 obj <>>>/Parent 5 0 R>> endobj 5 0 obj <> endobj 6 0 obj <> endobj xref 0 7 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000131 00000 n 000000{:04} 00000 n 000000{:04} 00000 n 000000{:04} 00000 n trailer <> startxref {:04} %%EOF "#, xmp_bytes.len(), xmp, xmp_bytes.len() + 179, xmp_bytes.len() + 336, xmp_bytes.len() + 425, xmp_bytes.len() + 518 ); write_pdf("tests/document_model/fixtures/pdfa_1b_conformance.pdf", &pdf); println!("Created pdfa_1b_conformance.pdf (XMP PDF/A-1B metadata)"); } /// Create page labels: pages 0-3 roman, pages 4+ arabic fn create_page_labels_roman_arabic() { let pdf = format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td (Page i) Tj ET endstream endobj 3 0 obj <>stream BT /F1 12 Tf 100 700 Td (Page ii) Tj ET endstream endobj 4 0 obj <>stream BT /F1 12 Tf 100 700 Td (Page iii) Tj ET endstream endobj 5 0 obj <>stream BT /F1 12 Tf 100 700 Td (Page iv) Tj ET endstream endobj 6 0 obj <>stream BT /F1 12 Tf 100 700 Td (Page 1) Tj ET endstream endobj 7 0 obj <>>>> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 13 0 obj <> endobj 14 0 obj <> endobj 15 0 obj <> endobj 16 0 obj <> endobj xref 0 17 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 0000000135 00000 n 0000000208 00000 n 0000000281 00000 n 0000000354 00000 n 0000000427 00000 n 0000000600 00000 n 0000000703 00000 n 0000000806 00000 n 0000000909 00000 n 0000001012 00000 n 0000001115 00000 n 0000001150 00000 n 0000001175 00000 n 0000001200 00000 n trailer <> startxref 1283 %%EOF "# ); write_pdf("tests/document_model/fixtures/page_labels_roman_arabic.pdf", &pdf); println!("Created page_labels_roman_arabic.pdf (roman 0-3, arabic 4+)"); } /// Create a minimal valid PDF document fn minimal_pdf(title: &str, content: &str) -> String { format!( r#"%PDF-1.4 1 0 obj <> endobj 2 0 obj <>stream BT /F1 12 Tf 100 700 Td ({}) Tj ET endstream endobj 3 0 obj <>>>/Parent 4 0 R>> endobj 4 0 obj <> endobj 5 0 obj <> endobj xref 0 6 0000000000 65535 f 0000000009 00000 n 0000000062 00000 n 000000{:04} 00000 n 000000{:04} 00000 n 000000{:04} 00000 n trailer <> startxref {:04} %%EOF "#, content.len() + 30, content, content.len() + 135, content.len() + 264, content.len() + 357, content.len() + 446 ) } /// Write PDF content to a file fn write_pdf(path: &str, content: &str) { let mut file = File::create(path).expect("Failed to create PDF file"); file.write_all(content.as_bytes()).expect("Failed to write PDF content"); }