From 3844aedd932df16be623059cb64ed0ef7d751b70 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Thu, 21 Jun 2012 12:21:34 -0400 Subject: Add testing for page APIs --- libqpdf/QPDF_pages.cc | 39 ++- qpdf/qpdf.testcov | 2 + qpdf/qtest/qpdf.test | 22 ++ qpdf/qtest/qpdf/page_api_1-out.pdf | 168 +++++++++++++ qpdf/qtest/qpdf/page_api_1-out2.pdf | 146 +++++++++++ qpdf/qtest/qpdf/page_api_1.pdf | 472 ++++++++++++++++++++++++++++++++++++ qpdf/qtest/qpdf/page_api_2.out | 1 + qpdf/qtest/qpdf/page_api_2.pdf | 137 +++++++++++ qpdf/test_driver.cc | 150 ++++++++++++ 9 files changed, 1125 insertions(+), 12 deletions(-) create mode 100644 qpdf/qtest/qpdf/page_api_1-out.pdf create mode 100644 qpdf/qtest/qpdf/page_api_1-out2.pdf create mode 100644 qpdf/qtest/qpdf/page_api_1.pdf create mode 100644 qpdf/qtest/qpdf/page_api_2.out create mode 100644 qpdf/qtest/qpdf/page_api_2.pdf diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index 930e8bd1..ed16e2ef 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -126,18 +126,23 @@ QPDF::insertPageobjToPage(QPDFObjectHandle const& obj, int pos, bool check_duplicate) { ObjGen og(obj.getObjectID(), obj.getGeneration()); - bool duplicate = - (! this->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second); - if (duplicate && check_duplicate) - { - QTC::TC("qpdf", "QPDF duplicate page reference"); - setLastObjectDescription("page " + QUtil::int_to_string(pos) + - " (numbered from zero)", - og.obj, og.gen); - throw QPDFExc(qpdf_e_pages, this->file->getName(), - this->last_object_description, 0, - "duplicate page reference found;" - " this would cause loss of data"); + if (check_duplicate) + { + if (! this->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second) + { + QTC::TC("qpdf", "QPDF duplicate page reference"); + setLastObjectDescription("page " + QUtil::int_to_string(pos) + + " (numbered from zero)", + og.obj, og.gen); + throw QPDFExc(qpdf_e_pages, this->file->getName(), + this->last_object_description, 0, + "duplicate page reference found;" + " this would cause loss of data"); + } + } + else + { + this->pageobj_to_pages_pos[og] = pos; } } @@ -150,6 +155,16 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) flattenPagesTree(); newpage.assertPageObject(); + if (! newpage.isIndirect()) + { + QTC::TC("qpdf", "QPDF insert non-indirect page"); + newpage = this->makeIndirectObject(newpage); + } + else + { + QTC::TC("qpdf", "QPDF insert indirect page"); + } + QTC::TC("qpdf", "QPDF insert page", (pos == 0) ? 0 : // insert at beginning (pos == ((int)this->all_pages.size())) ? 1 : // insert at end diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 249497a3..c7207bc8 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -207,3 +207,5 @@ QPDF duplicate page reference 0 QPDF remove page 2 QPDF insert page 2 QPDF updateAllPagesCache 0 +QPDF insert non-indirect page 0 +QPDF insert indirect page 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 03e114f7..bc0d5643 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -110,6 +110,28 @@ $td->runtest("new stream", show_ntests(); # ---------- +$td->notify("--- Page API Tests ---"); +$n_tests += 5; + +$td->runtest("basic page API", + {$td->COMMAND => "test_driver 15 page_api_1.pdf"}, + {$td->STRING => "test 15 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "page_api_1-out.pdf"}); +$td->runtest("manual page manipulation", + {$td->COMMAND => "test_driver 16 page_api_1.pdf"}, + {$td->STRING => "test 16 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "page_api_1-out2.pdf"}); +$td->runtest("duplicate page", + {$td->COMMAND => "test_driver 17 page_api_2.pdf"}, + {$td->FILE => "page_api_2.out", $td->EXIT_STATUS => 2}, + $td->NORMALIZE_NEWLINES); +# ---------- $td->notify("--- Miscellaneous Tests ---"); $n_tests += 37; diff --git a/qpdf/qtest/qpdf/page_api_1-out.pdf b/qpdf/qtest/qpdf/page_api_1-out.pdf new file mode 100644 index 00000000..b5439712 --- /dev/null +++ b/qpdf/qtest/qpdf/page_api_1-out.pdf @@ -0,0 +1,168 @@ +%PDF-1.3 +%¿÷¢þ +1 0 obj +<< /Pages 3 0 R /Type /Catalog >> +endobj +2 0 obj +<< /CreationDate (D:20120621111522) /Producer (Apex PDFWriter) >> +endobj +3 0 obj +<< /Count 13 /Kids [ 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R ] /Type /Pages >> +endobj +4 0 obj +<< /Contents 17 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +5 0 obj +<< /Contents 19 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +6 0 obj +<< /Contents 20 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +7 0 obj +<< /Contents 21 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +8 0 obj +<< /Contents 22 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +9 0 obj +<< /Contents 23 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +10 0 obj +<< /Contents 24 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +11 0 obj +<< /Contents 25 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +12 0 obj +<< /Contents 26 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +13 0 obj +<< /Contents 27 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +14 0 obj +<< /Contents 28 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +15 0 obj +<< /Contents 29 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +16 0 obj +<< /Contents 30 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 18 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +17 0 obj +<< /Length 42 >> +stream +BT /F1 15 Tf 72 720 Td (New page 0) Tj ET +endstream +endobj +18 0 obj +<< /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >> +endobj +19 0 obj +<< /Length 42 >> +stream +BT /F1 15 Tf 72 720 Td (New page 1) Tj ET +endstream +endobj +20 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 1) Tj ET +endstream +endobj +21 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET +endstream +endobj +22 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET +endstream +endobj +23 0 obj +<< /Length 42 >> +stream +BT /F1 15 Tf 72 720 Td (New page 5) Tj ET +endstream +endobj +24 0 obj +<< /Length 42 >> +stream +BT /F1 15 Tf 72 720 Td (New page 6) Tj ET +endstream +endobj +25 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 4) Tj ET +endstream +endobj +26 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 6) Tj ET +endstream +endobj +27 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 7) Tj ET +endstream +endobj +28 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 8) Tj ET +endstream +endobj +29 0 obj +<< /Length 43 >> +stream +BT /F1 15 Tf 72 720 Td (New page 11) Tj ET +endstream +endobj +30 0 obj +<< /Length 43 >> +stream +BT /F1 15 Tf 72 720 Td (New page 12) Tj ET +endstream +endobj +xref +0 31 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000145 00000 n +0000000284 00000 n +0000000438 00000 n +0000000592 00000 n +0000000746 00000 n +0000000900 00000 n +0000001054 00000 n +0000001208 00000 n +0000001363 00000 n +0000001518 00000 n +0000001673 00000 n +0000001828 00000 n +0000001983 00000 n +0000002138 00000 n +0000002293 00000 n +0000002385 00000 n +0000002485 00000 n +0000002577 00000 n +0000002674 00000 n +0000002771 00000 n +0000002868 00000 n +0000002960 00000 n +0000003052 00000 n +0000003149 00000 n +0000003246 00000 n +0000003343 00000 n +0000003440 00000 n +0000003533 00000 n +trailer << /Info 2 0 R /Root 1 0 R /Size 31 /ID [<21f7a6fb083dab8e29743918a08bfa31><31415926535897932384626433832795>] >> +startxref +3626 +%%EOF diff --git a/qpdf/qtest/qpdf/page_api_1-out2.pdf b/qpdf/qtest/qpdf/page_api_1-out2.pdf new file mode 100644 index 00000000..7ec2142e --- /dev/null +++ b/qpdf/qtest/qpdf/page_api_1-out2.pdf @@ -0,0 +1,146 @@ +%PDF-1.3 +%¿÷¢þ +1 0 obj +<< /Pages 3 0 R /Type /Catalog >> +endobj +2 0 obj +<< /CreationDate (D:20120621111522) /Producer (Apex PDFWriter) >> +endobj +3 0 obj +<< /Count 11 /Kids [ 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R ] /Type /Pages >> +endobj +4 0 obj +<< /Contents 15 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +5 0 obj +<< /Contents 17 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +6 0 obj +<< /Contents 18 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +7 0 obj +<< /Contents 19 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +8 0 obj +<< /Contents 20 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +9 0 obj +<< /Contents 21 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +10 0 obj +<< /Contents 22 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +11 0 obj +<< /Contents 23 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +12 0 obj +<< /Contents 24 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +13 0 obj +<< /Contents 25 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +14 0 obj +<< /Contents 26 0 R /MediaBox [ 0 0 612 792 ] /Parent 3 0 R /Resources << /Font << /F1 16 0 R >> /ProcSet [ /PDF /Text ] >> /Type /Page >> +endobj +15 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 0) Tj ET +endstream +endobj +16 0 obj +<< /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >> +endobj +17 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 1) Tj ET +endstream +endobj +18 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET +endstream +endobj +19 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET +endstream +endobj +20 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 4) Tj ET +endstream +endobj +21 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 5) Tj ET +endstream +endobj +22 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 6) Tj ET +endstream +endobj +23 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 7) Tj ET +endstream +endobj +24 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 8) Tj ET +endstream +endobj +25 0 obj +<< /Length 47 >> +stream +BT /F1 15 Tf 72 720 Td (Original page 9) Tj ET +endstream +endobj +26 0 obj +<< /Length 43 >> +stream +BT /F1 15 Tf 72 720 Td (New page 10) Tj ET +endstream +endobj +xref +0 27 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000145 00000 n +0000000270 00000 n +0000000424 00000 n +0000000578 00000 n +0000000732 00000 n +0000000886 00000 n +0000001040 00000 n +0000001194 00000 n +0000001349 00000 n +0000001504 00000 n +0000001659 00000 n +0000001814 00000 n +0000001969 00000 n +0000002066 00000 n +0000002166 00000 n +0000002263 00000 n +0000002360 00000 n +0000002457 00000 n +0000002554 00000 n +0000002651 00000 n +0000002748 00000 n +0000002845 00000 n +0000002942 00000 n +0000003039 00000 n +trailer << /Info 2 0 R /Root 1 0 R /Size 27 /ID [<21f7a6fb083dab8e29743918a08bfa31><31415926535897932384626433832795>] >> +startxref +3132 +%%EOF diff --git a/qpdf/qtest/qpdf/page_api_1.pdf b/qpdf/qtest/qpdf/page_api_1.pdf new file mode 100644 index 00000000..8abe106c --- /dev/null +++ b/qpdf/qtest/qpdf/page_api_1.pdf @@ -0,0 +1,472 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Pages 3 0 R + /Type /Catalog +>> +endobj + +2 0 obj +<< + /CreationDate (D:20120621111522) + /Producer (Apex PDFWriter) +>> +endobj + +3 0 obj +<< + /Count 10 + /Kids [ + 4 0 R + 5 0 R + 6 0 R + 7 0 R + 8 0 R + 9 0 R + 10 0 R + 11 0 R + 12 0 R + 13 0 R + ] + /Type /Pages +>> +endobj + +%% Page 1 +4 0 obj +<< + /Contents 14 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 2 +5 0 obj +<< + /Contents 17 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 3 +6 0 obj +<< + /Contents 19 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 4 +7 0 obj +<< + /Contents 21 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 5 +8 0 obj +<< + /Contents 23 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 6 +9 0 obj +<< + /Contents 25 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 7 +10 0 obj +<< + /Contents 27 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 8 +11 0 obj +<< + /Contents 29 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 9 +12 0 obj +<< + /Contents 31 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 10 +13 0 obj +<< + /Contents 33 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 16 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Contents for page 1 +14 0 obj +<< + /Length 15 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 0) Tj ET +endstream +endobj + +15 0 obj +47 +endobj + +16 0 obj +<< + /BaseFont /Times-Roman + /Encoding /WinAnsiEncoding + /Subtype /Type1 + /Type /Font +>> +endobj + +%% Contents for page 2 +17 0 obj +<< + /Length 18 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 1) Tj ET +endstream +endobj + +18 0 obj +47 +endobj + +%% Contents for page 3 +19 0 obj +<< + /Length 20 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET +endstream +endobj + +20 0 obj +47 +endobj + +%% Contents for page 4 +21 0 obj +<< + /Length 22 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET +endstream +endobj + +22 0 obj +47 +endobj + +%% Contents for page 5 +23 0 obj +<< + /Length 24 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 4) Tj ET +endstream +endobj + +24 0 obj +47 +endobj + +%% Contents for page 6 +25 0 obj +<< + /Length 26 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 5) Tj ET +endstream +endobj + +26 0 obj +47 +endobj + +%% Contents for page 7 +27 0 obj +<< + /Length 28 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 6) Tj ET +endstream +endobj + +28 0 obj +47 +endobj + +%% Contents for page 8 +29 0 obj +<< + /Length 30 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 7) Tj ET +endstream +endobj + +30 0 obj +47 +endobj + +%% Contents for page 9 +31 0 obj +<< + /Length 32 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 8) Tj ET +endstream +endobj + +32 0 obj +47 +endobj + +%% Contents for page 10 +33 0 obj +<< + /Length 34 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 9) Tj ET +endstream +endobj + +34 0 obj +47 +endobj + +xref +0 35 +0000000000 65535 f +0000000025 00000 n +0000000079 00000 n +0000000165 00000 n +0000000342 00000 n +0000000571 00000 n +0000000800 00000 n +0000001029 00000 n +0000001258 00000 n +0000001487 00000 n +0000001716 00000 n +0000001946 00000 n +0000002176 00000 n +0000002407 00000 n +0000002650 00000 n +0000002754 00000 n +0000002774 00000 n +0000002906 00000 n +0000003010 00000 n +0000003053 00000 n +0000003157 00000 n +0000003200 00000 n +0000003304 00000 n +0000003347 00000 n +0000003451 00000 n +0000003494 00000 n +0000003598 00000 n +0000003641 00000 n +0000003745 00000 n +0000003788 00000 n +0000003892 00000 n +0000003935 00000 n +0000004039 00000 n +0000004083 00000 n +0000004187 00000 n +trailer << + /Info 2 0 R + /Root 1 0 R + /Size 35 + /ID [<21f7a6fb083dab8e29743918a08bfa31><21f7a6fb083dab8e29743918a08bfa31>] +>> +startxref +4207 +%%EOF diff --git a/qpdf/qtest/qpdf/page_api_2.out b/qpdf/qtest/qpdf/page_api_2.out new file mode 100644 index 00000000..9fc019c2 --- /dev/null +++ b/qpdf/qtest/qpdf/page_api_2.out @@ -0,0 +1 @@ +page_api_2.pdf (page 1 (numbered from zero): object 4 0): duplicate page reference found; this would cause loss of data diff --git a/qpdf/qtest/qpdf/page_api_2.pdf b/qpdf/qtest/qpdf/page_api_2.pdf new file mode 100644 index 00000000..f3d6eaac --- /dev/null +++ b/qpdf/qtest/qpdf/page_api_2.pdf @@ -0,0 +1,137 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Pages 3 0 R + /Type /Catalog +>> +endobj + +2 0 obj +<< + /CreationDate (D:20120621124041) + /Producer (Apex PDFWriter) +>> +endobj + +3 0 obj +<< + /Count 3 + /Kids [ + 4 0 R + 4 0 R + 5 0 R + ] + /Type /Pages +>> +endobj + +%% Page 2 +4 0 obj +<< + /Contents 6 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 8 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 3 +5 0 obj +<< + /Contents 9 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 3 0 R + /Resources << + /Font << + /F1 8 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Contents for page 2 +6 0 obj +<< + /Length 7 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 0) Tj ET +endstream +endobj + +7 0 obj +47 +endobj + +8 0 obj +<< + /BaseFont /Times-Roman + /Encoding /WinAnsiEncoding + /Subtype /Type1 + /Type /Font +>> +endobj + +%% Contents for page 3 +9 0 obj +<< + /Length 10 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET +endstream +endobj + +10 0 obj +47 +endobj + +xref +0 11 +0000000000 65535 f +0000000025 00000 n +0000000079 00000 n +0000000165 00000 n +0000000267 00000 n +0000000494 00000 n +0000000734 00000 n +0000000836 00000 n +0000000855 00000 n +0000000986 00000 n +0000001089 00000 n +trailer << + /Info 2 0 R + /Root 1 0 R + /Size 11 + /ID [] +>> +startxref +1109 +%%EOF diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 2dc41b41..24e2f1ec 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include static char const* whoami = 0; @@ -56,8 +57,34 @@ class Provider: public QPDFObjectHandle::StreamDataProvider bool bad_length; }; +static void checkPageContents(QPDFObjectHandle page, + std::string const& wanted_string) +{ + PointerHolder b1 = + page.getKey("/Contents").getStreamData(); + std::string contents = std::string((char *)(b1->getBuffer())); + if (contents.find(wanted_string) == std::string::npos) + { + std::cout << "didn't find " << wanted_string << " in " + << contents << std::endl; + } +} + +static QPDFObjectHandle createPageContents(QPDF& pdf, std::string const& text) +{ + std::string contents = "BT /F1 15 Tf 72 720 Td (" + text + ") Tj ET\n"; + PointerHolder b = new Buffer(contents.length()); + unsigned char* bp = b->getBuffer(); + memcpy(bp, (char*)contents.c_str(), contents.length()); + return QPDFObjectHandle::newStream(&pdf, b); +} + void runtest(int n, char const* filename) { + // Most tests here are crafted to work on specific files. Look at + // the test suite to see how the test is invoked to find the file + // that the test is supposed to operate on. + QPDF pdf; PointerHolder file_buf; FILE* filep = 0; @@ -629,6 +656,129 @@ void runtest(int n, char const* filename) fclose(f); delete b; } + else if (n == 15) + { + std::vector const& pages = pdf.getAllPages(); + // Reference to original page numbers for this test case are + // numbered from 0. + + // Remove pages from various places, checking to make sure + // that our pages reference is getting updated. + assert(pages.size() == 10); + pdf.removePage(pages.back()); // original page 9 + assert(pages.size() == 9); + pdf.removePage(*pages.begin()); // original page 0 + assert(pages.size() == 8); + checkPageContents(pages[4], "Original page 5"); + pdf.removePage(pages[4]); // original page 5 + assert(pages.size() == 7); + checkPageContents(pages[4], "Original page 6"); + checkPageContents(pages[0], "Original page 1"); + checkPageContents(pages[6], "Original page 8"); + + // Insert pages + + // Create some content streams. + std::vector contents; + contents.push_back(createPageContents(pdf, "New page 1")); + contents.push_back(createPageContents(pdf, "New page 0")); + contents.push_back(createPageContents(pdf, "New page 5")); + contents.push_back(createPageContents(pdf, "New page 6")); + contents.push_back(createPageContents(pdf, "New page 11")); + contents.push_back(createPageContents(pdf, "New page 12")); + + // Create some page objects. Start with an existing + // dictionary and modify it. Using the results of + // getDictAsMap to create a new dictionary effectively creates + // a shallow copy. + std::map page_dict_keys = + QPDFObjectHandle(pages[0]).getDictAsMap(); + std::vector new_pages; + for (std::vector::iterator iter = contents.begin(); + iter != contents.end(); ++iter) + { + // We will retain indirect object references to other + // indirect objects other than page content. + page_dict_keys["/Contents"] = *iter; + QPDFObjectHandle page = + QPDFObjectHandle::newDictionary(page_dict_keys); + if (iter == contents.begin()) + { + // leave direct + new_pages.push_back(page); + } + else + { + new_pages.push_back(pdf.makeIndirectObject(page)); + } + } + + // Now insert the pages + pdf.addPage(new_pages[0], true); + checkPageContents(pages[0], "New page 1"); + pdf.addPageAt(new_pages[1], true, pages[0]); + assert(pages[0].getObjectID() == new_pages[1].getObjectID()); + pdf.addPageAt(new_pages[2], true, pages[5]); + assert(pages[5].getObjectID() == new_pages[2].getObjectID()); + pdf.addPageAt(new_pages[3], false, pages[5]); + assert(pages[6].getObjectID() == new_pages[3].getObjectID()); + assert(pages.size() == 11); + pdf.addPage(new_pages[4], false); + assert(pages[11].getObjectID() == new_pages[4].getObjectID()); + pdf.addPageAt(new_pages[5], false, pages.back()); + assert(pages.size() == 13); + checkPageContents(pages[0], "New page 0"); + checkPageContents(pages[1], "New page 1"); + checkPageContents(pages[5], "New page 5"); + checkPageContents(pages[6], "New page 6"); + checkPageContents(pages[11], "New page 11"); + checkPageContents(pages[12], "New page 12"); + + QPDFWriter w(pdf, "a.pdf"); + w.setStaticID(true); + w.setStreamDataMode(qpdf_s_preserve); + w.write(); + } + else if (n == 16) + { + // Insert a page manually and then update the cache. + std::vector const& all_pages = pdf.getAllPages(); + + QPDFObjectHandle contents = createPageContents(pdf, "New page 10"); + std::map page_dict_keys = + QPDFObjectHandle(all_pages[0]).getDictAsMap(); + page_dict_keys["/Contents"] = contents; + QPDFObjectHandle page = + pdf.makeIndirectObject( + QPDFObjectHandle::newDictionary(page_dict_keys)); + + // Insert the page manually. + QPDFObjectHandle root = pdf.getRoot(); + QPDFObjectHandle pages = root.getKey("/Pages"); + QPDFObjectHandle kids = pages.getKey("/Kids"); + page.replaceKey("/Parent", pages); + pages.replaceKey( + "/Count", + QPDFObjectHandle::newInteger(1 + (int)all_pages.size())); + kids.appendItem(page); + assert(all_pages.size() == 10); + pdf.updateAllPagesCache(); + assert(all_pages.size() == 11); + assert(all_pages.back().getObjectID() == page.getObjectID()); + + QPDFWriter w(pdf, "a.pdf"); + w.setStaticID(true); + w.setStreamDataMode(qpdf_s_preserve); + w.write(); + } + else if (n == 17) + { + // The input file to this test case is broken to exercise an + // error condition. + std::vector const& pages = pdf.getAllPages(); + pdf.removePage(pages[0]); + std::cout << "you can't see this" << std::endl; + } else { throw std::runtime_error(std::string("invalid test ") + -- cgit v1.2.3-54-g00ecf