diff options
author | Jay Berkenbilt <ejb@ql.org> | 2020-11-29 01:48:07 +0100 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2020-11-29 01:48:07 +0100 |
commit | 20509770999f705c25670bb14a8bb83aa1cc5b96 (patch) | |
tree | 58611570d449aae74f2f1ab61fbb97ab24300d25 /qpdf | |
parent | 78b9d6bfd4cbd3e947b1c5ffe73eb97b040e312a (diff) | |
download | qpdf-20509770999f705c25670bb14a8bb83aa1cc5b96.tar.zst |
Add QPDFObjectHandle manipulation to C API
Diffstat (limited to 'qpdf')
-rw-r--r-- | qpdf/qpdf-ctest.c | 172 | ||||
-rw-r--r-- | qpdf/qpdf.testcov | 64 | ||||
-rw-r--r-- | qpdf/qtest/qpdf.test | 15 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/c-object-handles-out.pdf | 104 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/c-object-handles.out | 24 |
5 files changed, 379 insertions, 0 deletions
diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c index fad121af..361a2070 100644 --- a/qpdf/qpdf-ctest.c +++ b/qpdf/qpdf-ctest.c @@ -495,6 +495,177 @@ static void test23(char const* infile, report_errors(); } +static void test24(char const* infile, + char const* password, + char const* outfile, + char const* outfile2) +{ + /* This test case is designed for minimal.pdf. */ + qpdf_read(qpdf, infile, password); + qpdf_oh trailer = qpdf_get_trailer(qpdf); + /* The library never returns 0 */ + assert(trailer == 1); + qpdf_oh root = qpdf_get_root(qpdf); + assert(qpdf_oh_get_generation(qpdf, root) == 0); + qpdf_oh root_from_trailer = qpdf_oh_get_key(qpdf, trailer, "/Root"); + assert(qpdf_oh_get_object_id(qpdf, root) == + qpdf_oh_get_object_id(qpdf, root_from_trailer)); + qpdf_oh pages = qpdf_oh_get_key(qpdf, root, "/Pages"); + assert(qpdf_oh_is_dictionary(qpdf, pages)); + qpdf_oh kids = qpdf_oh_get_key(qpdf, pages, "/Kids"); + assert(qpdf_oh_is_array(qpdf, kids)); + assert(qpdf_oh_get_array_n_items(qpdf, kids) == 1); + qpdf_oh page1 = qpdf_oh_get_array_item(qpdf, kids, 0); + qpdf_oh_begin_dict_key_iter(qpdf, page1); + while (qpdf_oh_dict_more_keys(qpdf)) + { + printf("page dictionary key: %s\n", qpdf_oh_dict_next_key(qpdf)); + } + qpdf_oh type = qpdf_oh_get_key(qpdf, page1, "/Type"); + assert(qpdf_oh_is_name(qpdf, type)); + assert(strcmp(qpdf_oh_get_name(qpdf, type), "/Page") == 0); + qpdf_oh parent = qpdf_oh_get_key(qpdf, page1, "/Parent"); + assert(qpdf_oh_is_indirect(qpdf, parent)); + qpdf_oh mediabox = qpdf_oh_get_key(qpdf, page1, "/MediaBox"); + assert(! qpdf_oh_is_scalar(qpdf, mediabox)); + assert(qpdf_oh_is_array(qpdf, mediabox)); + assert(qpdf_oh_get_array_n_items(qpdf, mediabox) == 4); + assert(qpdf_oh_wrap_in_array(qpdf, mediabox) == mediabox); + for (int i = 0; i < 4; ++i) + { + qpdf_oh item = qpdf_oh_get_array_item(qpdf, mediabox, i); + printf("item %d: %d %.2f\n", + i, qpdf_oh_get_int_value_as_int(qpdf, item), + qpdf_oh_get_numeric_value(qpdf, item)); + qpdf_oh_release(qpdf, item); + } + qpdf_oh i2 = qpdf_oh_get_array_item(qpdf, mediabox, 2); + assert(qpdf_oh_get_int_value_as_int(qpdf, i2) == 612); + assert(qpdf_oh_get_int_value(qpdf, i2) == 612ll); + assert(qpdf_oh_get_uint_value_as_uint(qpdf, i2) == 612u); + assert(qpdf_oh_get_uint_value(qpdf, i2) == 612ull); + assert(! qpdf_oh_is_operator(qpdf, i2)); + assert(! qpdf_oh_is_inline_image(qpdf, i2)); + qpdf_oh encoding = qpdf_oh_get_key( + qpdf, qpdf_oh_get_key( + qpdf, qpdf_oh_get_key( + qpdf, qpdf_oh_get_key( + qpdf, page1, "/Resources"), + "/Font"), + "/F1"), + "/Encoding"); + assert(strcmp(qpdf_oh_get_name(qpdf, encoding), "/WinAnsiEncoding") == 0); + qpdf_oh contents = qpdf_oh_get_key(qpdf, page1, "/Contents"); + assert(qpdf_oh_is_stream(qpdf, contents)); + qpdf_oh contents_dict = qpdf_oh_get_dict(qpdf, contents); + assert(! qpdf_oh_is_scalar(qpdf, contents)); + assert(! qpdf_oh_is_scalar(qpdf, contents_dict)); + qpdf_oh contents_length = qpdf_oh_get_key(qpdf, contents_dict, "/Length"); + assert(qpdf_oh_is_integer(qpdf, contents_length)); + assert(qpdf_oh_is_scalar(qpdf, contents_length)); + assert(qpdf_oh_is_number(qpdf, contents_length)); + qpdf_oh contents_array = qpdf_oh_wrap_in_array(qpdf, contents); + assert(qpdf_oh_get_array_n_items(qpdf, contents_array) == 1); + assert(qpdf_oh_get_object_id( + qpdf, qpdf_oh_get_array_item(qpdf, contents_array, 0)) == + qpdf_oh_get_object_id(qpdf, contents)); + qpdf_oh resources = qpdf_oh_get_key(qpdf, page1, "/Resources"); + qpdf_oh procset = qpdf_oh_get_key(qpdf, resources, "/ProcSet"); + assert(strcmp(qpdf_oh_unparse(qpdf, procset), + "5 0 R") == 0); + assert(strcmp(qpdf_oh_unparse_resolved(qpdf, procset), + "[ /PDF /Text ]") == 0); + qpdf_oh_make_direct(qpdf, procset); + assert(strcmp(qpdf_oh_unparse(qpdf, procset), + "[ /PDF /Text ]") == 0); + qpdf_oh_replace_key(qpdf, resources, "/ProcSet", procset); + + qpdf_oh parsed = qpdf_oh_parse( + qpdf, "[ 1 2.0 (3\xf7) << /Four [/Five] >> null true ]"); + qpdf_oh p_int = qpdf_oh_get_array_item(qpdf, parsed, 0); + qpdf_oh p_real = qpdf_oh_get_array_item(qpdf, parsed, 1); + qpdf_oh p_string = qpdf_oh_get_array_item(qpdf, parsed, 2); + qpdf_oh p_dict = qpdf_oh_get_array_item(qpdf, parsed, 3); + qpdf_oh p_null = qpdf_oh_get_array_item(qpdf, parsed, 4); + qpdf_oh p_bool = qpdf_oh_get_array_item(qpdf, parsed, 5); + assert(qpdf_oh_is_integer(qpdf, p_int) && + qpdf_oh_get_int_value_as_int(qpdf, p_int) == 1); + assert(qpdf_oh_is_real(qpdf, p_real) && + (strcmp(qpdf_oh_get_real_value(qpdf, p_real), "2.0") == 0) && + qpdf_oh_get_numeric_value(qpdf, p_real) == 2.0); + assert(qpdf_oh_is_string(qpdf, p_string) && + (strcmp(qpdf_oh_get_string_value(qpdf, p_string), "3\xf7") == 0) && + (strcmp(qpdf_oh_get_utf8_value(qpdf, p_string), "3\xc3\xb7") == 0) && + (strcmp(qpdf_oh_unparse_binary(qpdf, p_string), "<33f7>") == 0)); + assert(qpdf_oh_is_dictionary(qpdf, p_dict)); + qpdf_oh p_five = qpdf_oh_get_key(qpdf, p_dict, "/Four"); + assert(qpdf_oh_is_or_has_name(qpdf, p_five, "/Five")); + assert(qpdf_oh_is_or_has_name( + qpdf, qpdf_oh_get_array_item(qpdf, p_five, 0), "/Five")); + assert(qpdf_oh_is_null(qpdf, p_null)); + assert(qpdf_oh_is_bool(qpdf, p_bool) && + (qpdf_oh_get_bool_value(qpdf, p_bool) == QPDF_TRUE)); + qpdf_oh_erase_item(qpdf, parsed, 4); + qpdf_oh_insert_item( + qpdf, parsed, 2, + qpdf_oh_parse(qpdf, "<</A 1 /B 2 /C 3 /D 4>>")); + qpdf_oh new_dict = qpdf_oh_get_array_item(qpdf, parsed, 2); + assert(qpdf_oh_has_key(qpdf, new_dict, "/A")); + assert(qpdf_oh_has_key(qpdf, new_dict, "/D")); + qpdf_oh new_array = qpdf_oh_new_array(qpdf); + qpdf_oh_replace_or_remove_key( + qpdf, new_dict, "/A", qpdf_oh_new_null(qpdf)); + qpdf_oh_replace_or_remove_key( + qpdf, new_dict, "/B", new_array); + qpdf_oh_replace_key( + qpdf, new_dict, "/C", qpdf_oh_new_dictionary(qpdf)); + qpdf_oh_remove_key(qpdf, new_dict, "/D"); + assert(! qpdf_oh_has_key(qpdf, new_dict, "/A")); + assert(! qpdf_oh_has_key(qpdf, new_dict, "/D")); + qpdf_oh_append_item( + qpdf, new_array, qpdf_oh_new_string(qpdf, "potato")); + qpdf_oh_append_item( + qpdf, new_array, + qpdf_oh_new_unicode_string(qpdf, "qww\xc3\xb7\xcf\x80")); + qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 2 */ + qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 3 */ + qpdf_oh_set_array_item( + qpdf, new_array, 2, + qpdf_oh_new_name(qpdf, "/Quack")); + qpdf_oh_append_item( + qpdf, new_array, + qpdf_oh_new_real_from_double(qpdf, 4.0, 2)); + qpdf_oh_append_item( + qpdf, new_array, + qpdf_oh_new_real_from_string(qpdf, "5.0")); + qpdf_oh_append_item( + qpdf, new_array, + qpdf_oh_new_integer(qpdf, 6)); + qpdf_oh_append_item( + qpdf, new_array, qpdf_oh_new_bool(qpdf, QPDF_TRUE)); + qpdf_oh_replace_key(qpdf, root, "/QTest", new_dict); + + /* Release and access to exercise warnings */ + qpdf_oh_release(qpdf, page1); + contents = qpdf_oh_get_key(qpdf, page1, "/Contents"); + assert(qpdf_oh_is_null(qpdf, contents)); + assert(qpdf_oh_is_array(qpdf, mediabox)); + qpdf_oh_release_all(qpdf); + assert(! qpdf_oh_is_null(qpdf, mediabox)); + assert(! qpdf_oh_is_array(qpdf, mediabox)); + /* Make sure something is assigned when we exit so we check that + * it gets properl freed. + */ + qpdf_get_root(qpdf); + + 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; @@ -558,6 +729,7 @@ int main(int argc, char* argv[]) (n == 21) ? test21 : (n == 22) ? test22 : (n == 23) ? test23 : + (n == 24) ? test24 : 0); if (fn == 0) diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 7a2da359..b109a162 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -457,3 +457,67 @@ QPDF copy foreign with data 1 QPDF copy foreign with foreign_stream 1 QPDFObjectHandle need_newline 1 qpdf pages range omitted with . 0 +qpdf-c invalid object handle 0 +qpdf-c called qpdf_oh_release 0 +qpdf-c called qpdf_oh_release_all 0 +qpdf-c called qpdf_get_trailer 0 +qpdf-c called qpdf_get_root 0 +qpdf-c called qpdf_oh_is_bool 0 +qpdf-c called qpdf_oh_is_null 0 +qpdf-c called qpdf_oh_is_integer 0 +qpdf-c called qpdf_oh_is_real 0 +qpdf-c called qpdf_oh_is_name 0 +qpdf-c called qpdf_oh_is_string 0 +qpdf-c called qpdf_oh_is_operator 0 +qpdf-c called qpdf_oh_is_inline_image 0 +qpdf-c called qpdf_oh_is_array 0 +qpdf-c called qpdf_oh_is_dictionary 0 +qpdf-c called qpdf_oh_is_stream 0 +qpdf-c called qpdf_oh_is_indirect 0 +qpdf-c called qpdf_oh_is_scalar 0 +qpdf-c array to wrap_in_array 0 +qpdf-c non-array to wrap_in_array 0 +qpdf-c called qpdf_oh_parse 0 +qpdf-c called qpdf_oh_get_bool_value 0 +qpdf-c called qpdf_oh_get_int_value 0 +qpdf-c called qpdf_oh_get_int_value_as_int 0 +qpdf-c called qpdf_oh_get_uint_value 0 +qpdf-c called qpdf_oh_get_uint_value_as_uint 0 +qpdf-c called qpdf_oh_get_real_value 0 +qpdf-c called qpdf_oh_is_number 0 +qpdf-c called qpdf_oh_get_numeric_value 0 +qpdf-c called qpdf_oh_get_name 0 +qpdf-c called qpdf_oh_get_string_value 0 +qpdf-c called qpdf_oh_get_utf8_value 0 +qpdf-c called qpdf_oh_get_array_n_items 0 +qpdf-c called qpdf_oh_get_array_item 0 +qpdf-c called qpdf_oh_begin_dict_key_iter 0 +qpdf-c called qpdf_oh_dict_more_keys 0 +qpdf-c called qpdf_oh_dict_next_key 0 +qpdf-c called qpdf_oh_has_key 0 +qpdf-c called qpdf_oh_get_key 0 +qpdf-c called qpdf_oh_is_or_has_name 0 +qpdf-c called qpdf_oh_new_null 0 +qpdf-c called qpdf_oh_new_bool 0 +qpdf-c called qpdf_oh_new_integer 0 +qpdf-c called qpdf_oh_new_real_from_string 0 +qpdf-c called qpdf_oh_new_real_from_double 0 +qpdf-c called qpdf_oh_new_name 0 +qpdf-c called qpdf_oh_new_string 0 +qpdf-c called qpdf_oh_new_unicode_string 0 +qpdf-c called qpdf_oh_new_array 0 +qpdf-c called qpdf_oh_new_dictionary 0 +qpdf-c called qpdf_oh_make_direct 0 +qpdf-c called qpdf_oh_set_array_item 0 +qpdf-c called qpdf_oh_insert_item 0 +qpdf-c called qpdf_oh_append_item 0 +qpdf-c called qpdf_oh_erase_item 0 +qpdf-c called qpdf_oh_replace_key 0 +qpdf-c called qpdf_oh_remove_key 0 +qpdf-c called qpdf_oh_replace_or_remove_key 0 +qpdf-c called qpdf_oh_get_dict 0 +qpdf-c called qpdf_oh_get_object_id 0 +qpdf-c called qpdf_oh_get_generation 0 +qpdf-c called qpdf_oh_unparse 0 +qpdf-c called qpdf_oh_unparse_resolved 0 +qpdf-c called qpdf_oh_unparse_binary 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 58f646f4..a786fa33 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -4120,6 +4120,21 @@ foreach my $i (@c_check_types) show_ntests(); # ---------- +$td->notify("--- C API Object Handle ---"); +$n_tests += scalar(@c_check_types); + +$td->runtest("C check object handles", + {$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"}, + {$td->FILE => "c-object-handles.out", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + +$td->runtest("check output", + {$td->FILE => 'a.pdf'}, + {$td->FILE => 'c-object-handles-out.pdf'}); + +show_ntests(); +# ---------- $td->notify("--- Content Preservation Tests ---"); # $n_tests incremented below diff --git a/qpdf/qtest/qpdf/c-object-handles-out.pdf b/qpdf/qtest/qpdf/c-object-handles-out.pdf new file mode 100644 index 00000000..596618b4 --- /dev/null +++ b/qpdf/qtest/qpdf/c-object-handles-out.pdf @@ -0,0 +1,104 @@ +%PDF-1.3 +%¿÷¢þ +%QDF-1.0 + +1 0 obj +<< + /Pages 2 0 R + /QTest << + /B [ + (potato) + <feff00710077007700f703c0> + /Quack + null + 4.00 + 5.0 + 6 + true + ] + /C << + >> + >> + /Type /Catalog +>> +endobj + +2 0 obj +<< + /Count 1 + /Kids [ + 3 0 R + ] + /Type /Pages +>> +endobj + +%% Page 1 +3 0 obj +<< + /Contents 4 0 R + /MediaBox [ + 0 + 0 + 612 + 792 + ] + /Parent 2 0 R + /Resources << + /Font << + /F1 6 0 R + >> + /ProcSet [ + /PDF + /Text + ] + >> + /Type /Page +>> +endobj + +%% Contents for page 1 +4 0 obj +<< + /Length 5 0 R +>> +stream +BT + /F1 24 Tf + 72 720 Td + (Potato) Tj +ET +endstream +endobj + +5 0 obj +44 +endobj + +6 0 obj +<< + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding + /Name /F1 + /Subtype /Type1 + /Type /Font +>> +endobj + +xref +0 7 +0000000000 65535 f +0000000025 00000 n +0000000240 00000 n +0000000322 00000 n +0000000562 00000 n +0000000661 00000 n +0000000680 00000 n +trailer << + /Root 1 0 R + /Size 7 + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] +>> +startxref +798 +%%EOF diff --git a/qpdf/qtest/qpdf/c-object-handles.out b/qpdf/qtest/qpdf/c-object-handles.out new file mode 100644 index 00000000..7fef9dad --- /dev/null +++ b/qpdf/qtest/qpdf/c-object-handles.out @@ -0,0 +1,24 @@ +page dictionary key: /Contents +page dictionary key: /MediaBox +page dictionary key: /Parent +page dictionary key: /Resources +page dictionary key: /Type +item 0: 0 0.00 +item 1: 0 0.00 +item 2: 612 612.00 +item 3: 792 792.00 +warning: minimal.pdf (C API object handle 6): attempted access to unknown/uninitialized object handle + code: 5 + file: minimal.pdf + pos : 0 + text: attempted access to unknown/uninitialized object handle +warning: minimal.pdf (C API object handle 9): attempted access to unknown/uninitialized object handle + code: 5 + file: minimal.pdf + pos : 0 + text: attempted access to unknown/uninitialized object handle +warning: minimal.pdf (C API object handle 9): attempted access to unknown/uninitialized object handle + code: 5 + file: minimal.pdf + pos : 0 + text: attempted access to unknown/uninitialized object handle |