mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
C API: expose functions for indirect objects (fixes #588)
This commit is contained in:
parent
8e0b153332
commit
1c62c2a342
@ -1,5 +1,9 @@
|
||||
2021-12-10 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* C API: add qpdf_get_object_by_id, qpdf_make_indirect_object, and
|
||||
qpdf_replace_object, exposing the corresponding methods in QPDF
|
||||
and QPDFObjectHandle. Fixes #588.
|
||||
|
||||
* Add missing QPDF_DLL to QPDFObjectHandle::addTokenFilter so that
|
||||
it is actually accessible as part of the public interface as
|
||||
intended. Fixes #580.
|
||||
|
@ -618,6 +618,15 @@ extern "C" {
|
||||
QPDF_DLL
|
||||
qpdf_oh qpdf_get_root(qpdf_data data);
|
||||
|
||||
/* Retrieve and replace indirect objects */
|
||||
QPDF_DLL
|
||||
qpdf_oh qpdf_get_object_by_id(qpdf_data qpdf, int objid, int generation);
|
||||
QPDF_DLL
|
||||
qpdf_oh qpdf_make_indirect_object(qpdf_data qpdf, qpdf_oh oh);
|
||||
QPDF_DLL
|
||||
void qpdf_replace_object(
|
||||
qpdf_data qpdf, int objid, int generation, qpdf_oh oh);
|
||||
|
||||
/* Wrappers around QPDFObjectHandle methods. Be sure to read
|
||||
* corresponding comments in QPDFObjectHandle.hh to understand
|
||||
* what each function does and what kinds of objects it applies
|
||||
|
@ -972,6 +972,12 @@ qpdf_oh qpdf_get_root(qpdf_data qpdf)
|
||||
});
|
||||
}
|
||||
|
||||
qpdf_oh qpdf_get_object_by_id(qpdf_data qpdf, int objid, int generation)
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_get_object_by_id");
|
||||
return new_object(qpdf, qpdf->qpdf->getObjectByID(objid, generation));
|
||||
}
|
||||
|
||||
template<class RET>
|
||||
static RET do_with_oh(
|
||||
qpdf_data qpdf, qpdf_oh oh,
|
||||
@ -1008,6 +1014,15 @@ static void do_with_oh_void(
|
||||
});
|
||||
}
|
||||
|
||||
void qpdf_replace_object(qpdf_data qpdf, int objid, int generation, qpdf_oh oh)
|
||||
{
|
||||
do_with_oh_void(
|
||||
qpdf, oh, [&qpdf, &objid, &generation](QPDFObjectHandle& o) {
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_replace_object");
|
||||
qpdf->qpdf->replaceObject(objid, generation, o);
|
||||
});
|
||||
}
|
||||
|
||||
QPDF_BOOL qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh)
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized");
|
||||
@ -1421,6 +1436,16 @@ void qpdf_oh_make_direct(qpdf_data qpdf, qpdf_oh oh)
|
||||
});
|
||||
}
|
||||
|
||||
qpdf_oh qpdf_make_indirect_object(qpdf_data qpdf, qpdf_oh oh)
|
||||
{
|
||||
return do_with_oh<qpdf_oh>(
|
||||
qpdf, oh,
|
||||
return_uninitialized(qpdf),
|
||||
[&qpdf](QPDFObjectHandle& o) {
|
||||
return new_object(qpdf, qpdf->qpdf->makeIndirectObject(o));
|
||||
});
|
||||
}
|
||||
|
||||
static QPDFObjectHandle
|
||||
qpdf_oh_item_internal(qpdf_data qpdf, qpdf_oh item)
|
||||
{
|
||||
|
@ -5263,6 +5263,15 @@ print "\n";
|
||||
C API. This allows you to clone an object handle.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Add <function>qpdf_get_object_by_id</function>,
|
||||
<function>qpdf_make_indirect_object</function>, and
|
||||
<function>qpdf_replace_object</function>, exposing the
|
||||
corresponding methods in <classname>QPDF</classname> and
|
||||
<classname>QPDFObjectHandle</classname>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -881,6 +881,56 @@ static void test31(char const* infile,
|
||||
report_errors();
|
||||
}
|
||||
|
||||
static void test32(char const* infile,
|
||||
char const* password,
|
||||
char const* outfile,
|
||||
char const* outfile2)
|
||||
{
|
||||
/* This test case is designed for minimal.pdf. */
|
||||
assert(qpdf_read(qpdf, infile, password) == 0);
|
||||
qpdf_oh page = qpdf_get_object_by_id(qpdf, 3, 0);
|
||||
assert(qpdf_oh_is_dictionary(qpdf, page));
|
||||
assert(qpdf_oh_has_key(qpdf, page, "/MediaBox"));
|
||||
report_errors();
|
||||
}
|
||||
|
||||
static void test33(char const* infile,
|
||||
char const* password,
|
||||
char const* outfile,
|
||||
char const* outfile2)
|
||||
{
|
||||
/* This test case is designed for minimal.pdf. */
|
||||
|
||||
/* Convert a direct object to an indirect object and replace it. */
|
||||
assert(qpdf_read(qpdf, infile, password) == 0);
|
||||
qpdf_oh root = qpdf_get_root(qpdf);
|
||||
qpdf_oh pages = qpdf_oh_get_key(qpdf, root, "/Pages");
|
||||
qpdf_oh kids = qpdf_oh_get_key(qpdf, pages, "/Kids");
|
||||
qpdf_oh page1 = qpdf_oh_get_array_item(qpdf, kids, 0);
|
||||
qpdf_oh mediabox = qpdf_oh_get_key(qpdf, page1, "/MediaBox");
|
||||
assert(! qpdf_oh_is_indirect(qpdf, mediabox));
|
||||
qpdf_oh i_mediabox = qpdf_make_indirect_object(qpdf, mediabox);
|
||||
assert(qpdf_oh_is_indirect(qpdf, i_mediabox));
|
||||
qpdf_oh_replace_key(qpdf, page1, "/MediaBox", i_mediabox);
|
||||
|
||||
/* Replace a different indirect object */
|
||||
qpdf_oh resources = qpdf_oh_get_key(qpdf, page1, "/Resources");
|
||||
qpdf_oh procset = qpdf_oh_get_key(qpdf, resources, "/ProcSet");
|
||||
assert(qpdf_oh_is_indirect(qpdf, procset));
|
||||
qpdf_replace_object(
|
||||
qpdf,
|
||||
qpdf_oh_get_object_id(qpdf, procset),
|
||||
qpdf_oh_get_generation(qpdf, procset),
|
||||
qpdf_oh_parse(qpdf, "[/PDF]"));
|
||||
|
||||
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;
|
||||
@ -952,6 +1002,8 @@ int main(int argc, char* argv[])
|
||||
(n == 29) ? test29 :
|
||||
(n == 30) ? test30 :
|
||||
(n == 31) ? test31 :
|
||||
(n == 32) ? test32 :
|
||||
(n == 33) ? test33 :
|
||||
0);
|
||||
|
||||
if (fn == 0)
|
||||
|
@ -606,3 +606,5 @@ qpdf-c called qpdf_oh_new_uninitialized 0
|
||||
qpdf-c warn about oh error 1
|
||||
qpdf-c registered oh error handler 0
|
||||
qpdf-c cleanup warned about unhandled error 0
|
||||
qpdf-c called qpdf_get_object_by_id 0
|
||||
qpdf-c called qpdf_replace_object 0
|
||||
|
@ -4812,7 +4812,7 @@ foreach my $i (@c_check_types)
|
||||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- C API Object Handle ---");
|
||||
$n_tests += 10;
|
||||
$n_tests += 13;
|
||||
|
||||
$td->runtest("C check object handles",
|
||||
{$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"},
|
||||
@ -4831,6 +4831,14 @@ $td->runtest("check output",
|
||||
{$td->FILE => 'a.pdf'},
|
||||
{$td->FILE => 'c-object-handle-creation-out.pdf'});
|
||||
|
||||
$td->runtest("C indirect objects",
|
||||
{$td->COMMAND => "qpdf-ctest 33 minimal.pdf '' a.pdf"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("check output",
|
||||
{$td->FILE => 'a.pdf'},
|
||||
{$td->FILE => 'c-indirect-objects-out.pdf'});
|
||||
|
||||
$td->runtest("C uninitialized objects",
|
||||
{$td->COMMAND => "qpdf-ctest 26 '' '' ''"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||
@ -4855,6 +4863,10 @@ $td->runtest("C type mismatch warning",
|
||||
{$td->COMMAND => "qpdf-ctest 31 minimal.pdf '' ''"},
|
||||
{$td->FILE => "c-type-warning.out", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
$td->runtest("C get object by ID",
|
||||
{$td->COMMAND => "qpdf-ctest 32 minimal.pdf '' ''"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
show_ntests();
|
||||
# ----------
|
||||
|
99
qpdf/qtest/qpdf/c-indirect-objects-out.pdf
Normal file
99
qpdf/qtest/qpdf/c-indirect-objects-out.pdf
Normal file
@ -0,0 +1,99 @@
|
||||
%PDF-1.3
|
||||
%¿÷¢þ
|
||||
%QDF-1.0
|
||||
|
||||
1 0 obj
|
||||
<<
|
||||
/Pages 2 0 R
|
||||
/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 6 0 R
|
||||
/Parent 2 0 R
|
||||
/Resources <<
|
||||
/Font <<
|
||||
/F1 7 0 R
|
||||
>>
|
||||
/ProcSet 8 0 R
|
||||
>>
|
||||
/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
|
||||
[
|
||||
0
|
||||
0
|
||||
612
|
||||
792
|
||||
]
|
||||
endobj
|
||||
|
||||
7 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica
|
||||
/Encoding /WinAnsiEncoding
|
||||
/Name /F1
|
||||
/Subtype /Type1
|
||||
/Type /Font
|
||||
>>
|
||||
endobj
|
||||
|
||||
8 0 obj
|
||||
[
|
||||
/PDF
|
||||
]
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 9
|
||||
0000000000 65535 f
|
||||
0000000025 00000 n
|
||||
0000000079 00000 n
|
||||
0000000161 00000 n
|
||||
0000000348 00000 n
|
||||
0000000447 00000 n
|
||||
0000000466 00000 n
|
||||
0000000506 00000 n
|
||||
0000000624 00000 n
|
||||
trailer <<
|
||||
/Root 1 0 R
|
||||
/Size 9
|
||||
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
|
||||
>>
|
||||
startxref
|
||||
651
|
||||
%%EOF
|
Loading…
Reference in New Issue
Block a user