diff options
author | Jay Berkenbilt <ejb@ql.org> | 2021-12-17 19:28:11 +0100 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2021-12-17 19:28:11 +0100 |
commit | feafcc4e88798626c80840797822efbf55722716 (patch) | |
tree | 1eabc4f818084d56a25a9571d87823f8004c7b9f /qpdf | |
parent | a0dbb71a64e6adb26f8f02881e8d0ea8476ee875 (diff) | |
download | qpdf-feafcc4e88798626c80840797822efbf55722716.tar.zst |
C API: add several stream functions (fixes #596)
Diffstat (limited to 'qpdf')
-rw-r--r-- | qpdf/qpdf-ctest.c | 115 | ||||
-rw-r--r-- | qpdf/qpdf.testcov | 6 | ||||
-rw-r--r-- | qpdf/qtest/qpdf.test | 28 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/c-foreign.pdf | 573 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/c-get-stream.out | 13 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/c-new-stream.pdf | bin | 0 -> 1116 bytes |
6 files changed, 735 insertions, 0 deletions
diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c index 90ebdcd4..cf03f0e0 100644 --- a/qpdf/qpdf-ctest.c +++ b/qpdf/qpdf-ctest.c @@ -1063,6 +1063,118 @@ static void test37(char const* infile, assert(qpdf_get_num_pages(qpdf) == 10); } +static void test38(char const* infile, + char const* password, + char const* outfile, + char const* xarg) +{ + /* This test expects 11-pages.pdf. */ + + /* Read stream data */ + + assert(qpdf_read(qpdf, infile, password) == 0); + qpdf_oh stream = qpdf_get_object_by_id(qpdf, 17, 0); + qpdf_oh dict = qpdf_oh_get_dict(qpdf, stream); + assert(qpdf_oh_get_int_value_as_int( + qpdf, qpdf_oh_get_key(qpdf, dict, "/Length")) == 53); + /* Get raw data */ + unsigned char *buf = 0; + size_t len = 0; + assert(qpdf_oh_get_stream_data( + qpdf, stream, qpdf_dl_none, 0, &buf, &len) == 0); + assert(len == 53); + assert(((int)buf[0] == 'x') && ((int)buf[1] == 0234)); + free(buf); + + /* Test whether filterable */ + QPDF_BOOL filtered = QPDF_FALSE; + assert(qpdf_oh_get_stream_data( + qpdf, stream, qpdf_dl_all, &filtered, 0, 0) == 0); + assert(filtered == QPDF_TRUE); + + /* Get filtered data */ + assert(qpdf_oh_get_stream_data( + qpdf, stream, qpdf_dl_all, 0, &buf, &len) == 0); + assert(len == 47); + assert(memcmp((char const*)buf, + "BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET\n", + len) == 0); + + /* Get page data */ + qpdf_oh page2 = qpdf_get_page_n(qpdf, 1); /* 0-based index */ + unsigned char* buf2 = 0; + assert(qpdf_oh_get_page_content_data(qpdf, page2, &buf2, &len) == 0); + assert(len == 47); + assert(memcmp(buf, buf2, len) == 0); + free(buf); + free(buf2); + + /* errors */ + printf("page content on broken page\n"); + qpdf_oh_replace_key(qpdf, page2, "/Contents", qpdf_oh_new_integer(qpdf, 3)); + buf = 0; + qpdf_oh_get_page_content_data(qpdf, page2, &buf, &len); + assert(buf == 0); + report_errors(); + printf("stream data for non stream\n"); + qpdf_oh root = qpdf_get_root(qpdf); + assert(qpdf_oh_get_stream_data(qpdf, root, qpdf_dl_all, 0, 0, 0) != 0); + report_errors(); +} + +static void test39(char const* infile, + char const* password, + char const* outfile, + char const* xarg) +{ + /* This test expects 11-pages.pdf as file1 and minimal.pdf as xarg. */ + + /* Foreign object */ + + qpdf_data qpdf2 = qpdf_init(); + assert(qpdf_read(qpdf, infile, password) == 0); + assert(qpdf_read(qpdf2, xarg, "") == 0); + + qpdf_oh resources = qpdf_get_object_by_id(qpdf2, 3, 0); + qpdf_oh copy = qpdf_oh_copy_foreign_object(qpdf, qpdf2, resources); + qpdf_oh root = qpdf_get_root(qpdf); + qpdf_oh_replace_key(qpdf, root, "/Copy", copy); + + qpdf_init_write(qpdf, outfile); + qpdf_set_static_ID(qpdf, QPDF_TRUE); + qpdf_set_qdf_mode(qpdf, QPDF_TRUE); + qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE); + qpdf_write(qpdf); + report_errors(); + qpdf_cleanup(&qpdf2); +} + +static void test40(char const* infile, + char const* password, + char const* outfile, + char const* xarg) +{ + /* This test expects minimal.pdf. */ + + /* New stream */ + + assert(qpdf_read(qpdf, infile, password) == 0); + qpdf_oh stream = qpdf_oh_new_stream(qpdf); + qpdf_oh_replace_stream_data( + qpdf, stream, + (unsigned char*)"12345\000abcde", 11, /* embedded null */ + qpdf_oh_new_null(qpdf), qpdf_oh_new_null(qpdf)); + qpdf_oh root = qpdf_get_root(qpdf); + qpdf_oh_replace_key(qpdf, root, "/Potato", stream); + + qpdf_init_write(qpdf, outfile); + qpdf_set_static_ID(qpdf, QPDF_TRUE); + qpdf_set_qdf_mode(qpdf, QPDF_TRUE); + qpdf_set_suppress_original_object_IDs(qpdf, QPDF_TRUE); + qpdf_write(qpdf); + report_errors(); +} + int main(int argc, char* argv[]) { char* p = 0; @@ -1140,6 +1252,9 @@ int main(int argc, char* argv[]) (n == 35) ? test35 : (n == 36) ? test36 : (n == 37) ? test37 : + (n == 38) ? test38 : + (n == 39) ? test39 : + (n == 40) ? test40 : 0); if (fn == 0) diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 315c1200..ebe0d2b3 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -617,3 +617,9 @@ qpdf-c called qpdf_push_inherited_attributes_to_page 0 qpdf-c called qpdf_add_page 0 qpdf-c called qpdf_add_page_at 0 qpdf-c called qpdf_remove_page 0 +qpdf-c called qpdf_oh_new_stream 0 +qpdf-c called qpdf_oh_copy_foreign_object 0 +qpdf-c stream data filtered set 1 +qpdf-c stream data buf set 1 +qpdf-c called qpdf_oh_get_page_content_data 0 +qpdf-c called qpdf_oh_replace_stream_data 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 3825cfaa..a5d69a4b 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -4904,6 +4904,34 @@ $td->runtest("C pages cache", show_ntests(); # ---------- +$td->notify("--- C API Stream Functions ---"); +$n_tests += 5; + +$td->runtest("C read streams", + {$td->COMMAND => + "qpdf-ctest 38 11-pages.pdf '' ''"}, + {$td->FILE => "c-get-stream.out", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + +$td->runtest("C foreign object", + {$td->COMMAND => + "qpdf-ctest 39 11-pages.pdf '' a.pdf minimal.pdf"}, + {$td->STRING => "C test 39 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => 'a.pdf'}, + {$td->FILE => 'c-foreign.pdf'}); + +$td->runtest("C new stream", + {$td->COMMAND => + "qpdf-ctest 40 minimal.pdf '' a.pdf"}, + {$td->STRING => "C test 40 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => 'a.pdf'}, + {$td->FILE => 'c-new-stream.pdf'}); +show_ntests(); +# ---------- $td->notify("--- Content Preservation Tests ---"); # $n_tests incremented below diff --git a/qpdf/qtest/qpdf/c-foreign.pdf b/qpdf/qtest/qpdf/c-foreign.pdf new file mode 100644 index 00000000..662d9238 --- /dev/null +++ b/qpdf/qtest/qpdf/c-foreign.pdf @@ -0,0 +1,573 @@ +%PDF-1.4 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Copy 3 0 R + /Pages 4 0 R + /Type /Catalog +>> +endobj + +2 0 obj +<< + /CreationDate (D:20120721200217) + /Producer (Apex PDFWriter) +>> +endobj + +3 0 obj +<< + /Contents 5 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Resources << + /Font << + /F1 7 0 R + >> + /ProcSet 8 0 R + >> + /Type /Page +>> +endobj + +4 0 obj +<< + /Count 11 + /Kids [ + 9 0 R + 10 0 R + 11 0 R + 12 0 R + 13 0 R + 14 0 R + 15 0 R + 16 0 R + 17 0 R + 18 0 R + 19 0 R + ] + /Type /Pages +>> +endobj + +5 0 obj +<< + /Length 6 0 R +>> +stream +BT + /F1 24 Tf + 72 720 Td + (Potato) Tj +ET +endstream +endobj + +6 0 obj +44 +endobj + +7 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +8 0 obj +[ + /PDF + /Text +] +endobj + +%% Page 1 +9 0 obj +<< + /Contents 20 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 2 +10 0 obj +<< + /Contents 23 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 3 +11 0 obj +<< + /Contents 25 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 4 +12 0 obj +<< + /Contents 27 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 5 +13 0 obj +<< + /Contents 29 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 6 +14 0 obj +<< + /Contents 31 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 7 +15 0 obj +<< + /Contents 33 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 8 +16 0 obj +<< + /Contents 35 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 9 +17 0 obj +<< + /Contents 37 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 10 +18 0 obj +<< + /Contents 39 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Page 11 +19 0 obj +<< + /Contents 41 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 4 0 R + /Resources << + /Font << + /F1 22 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Contents for page 1 +20 0 obj +<< + /Length 21 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 1) Tj ET +endstream +endobj + +21 0 obj +47 +endobj + +22 0 obj +<< + /BaseFont /Times-Roman + /Encoding /WinAnsiEncoding + /Subtype /Type1 + /Type /Font +>> +endobj + +%% Contents for page 2 +23 0 obj +<< + /Length 24 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 2) Tj ET +endstream +endobj + +24 0 obj +47 +endobj + +%% Contents for page 3 +25 0 obj +<< + /Length 26 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 3) Tj ET +endstream +endobj + +26 0 obj +47 +endobj + +%% Contents for page 4 +27 0 obj +<< + /Length 28 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 4) Tj ET +endstream +endobj + +28 0 obj +47 +endobj + +%% Contents for page 5 +29 0 obj +<< + /Length 30 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 5) Tj ET +endstream +endobj + +30 0 obj +47 +endobj + +%% Contents for page 6 +31 0 obj +<< + /Length 32 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 6) Tj ET +endstream +endobj + +32 0 obj +47 +endobj + +%% Contents for page 7 +33 0 obj +<< + /Length 34 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 7) Tj ET +endstream +endobj + +34 0 obj +47 +endobj + +%% Contents for page 8 +35 0 obj +<< + /Length 36 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 8) Tj ET +endstream +endobj + +36 0 obj +47 +endobj + +%% Contents for page 9 +37 0 obj +<< + /Length 38 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 9) Tj ET +endstream +endobj + +38 0 obj +47 +endobj + +%% Contents for page 10 +39 0 obj +<< + /Length 40 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 10) Tj ET +endstream +endobj + +40 0 obj +48 +endobj + +%% Contents for page 11 +41 0 obj +<< + /Length 42 0 R +>> +stream +BT /F1 15 Tf 72 720 Td (Original page 11) Tj ET +endstream +endobj + +42 0 obj +48 +endobj + +xref +0 43 +0000000000 65535 f +0000000025 00000 n +0000000093 00000 n +0000000179 00000 n +0000000355 00000 n +0000000538 00000 n +0000000637 00000 n +0000000656 00000 n +0000000774 00000 n +0000000819 00000 n +0000001048 00000 n +0000001278 00000 n +0000001508 00000 n +0000001738 00000 n +0000001968 00000 n +0000002198 00000 n +0000002428 00000 n +0000002658 00000 n +0000002889 00000 n +0000003120 00000 n +0000003363 00000 n +0000003467 00000 n +0000003487 00000 n +0000003619 00000 n +0000003723 00000 n +0000003766 00000 n +0000003870 00000 n +0000003913 00000 n +0000004017 00000 n +0000004060 00000 n +0000004164 00000 n +0000004207 00000 n +0000004311 00000 n +0000004354 00000 n +0000004458 00000 n +0000004501 00000 n +0000004605 00000 n +0000004648 00000 n +0000004752 00000 n +0000004796 00000 n +0000004901 00000 n +0000004945 00000 n +0000005050 00000 n +trailer << + /Info 2 0 R + /Root 1 0 R + /Size 43 + /ID [<e032a88c7a987db6ca3abee555506ccc><31415926535897932384626433832795>] +>> +startxref +5070 +%%EOF diff --git a/qpdf/qtest/qpdf/c-get-stream.out b/qpdf/qtest/qpdf/c-get-stream.out new file mode 100644 index 00000000..e78bd4eb --- /dev/null +++ b/qpdf/qtest/qpdf/c-get-stream.out @@ -0,0 +1,13 @@ +page content on broken page +error: page object 5 0: object is supposed to be a stream or an array of streams but is neither + code: 5 + file: + pos : 0 + text: object is supposed to be a stream or an array of streams but is neither +stream data for non stream +error: operation for stream attempted on object of type dictionary + code: 2 + file: + pos : 0 + text: operation for stream attempted on object of type dictionary +C test 38 done diff --git a/qpdf/qtest/qpdf/c-new-stream.pdf b/qpdf/qtest/qpdf/c-new-stream.pdf Binary files differnew file mode 100644 index 00000000..95ff378f --- /dev/null +++ b/qpdf/qtest/qpdf/c-new-stream.pdf |