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>
|
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
|
* Add missing QPDF_DLL to QPDFObjectHandle::addTokenFilter so that
|
||||||
it is actually accessible as part of the public interface as
|
it is actually accessible as part of the public interface as
|
||||||
intended. Fixes #580.
|
intended. Fixes #580.
|
||||||
|
@ -618,6 +618,15 @@ extern "C" {
|
|||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
qpdf_oh qpdf_get_root(qpdf_data data);
|
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
|
/* Wrappers around QPDFObjectHandle methods. Be sure to read
|
||||||
* corresponding comments in QPDFObjectHandle.hh to understand
|
* corresponding comments in QPDFObjectHandle.hh to understand
|
||||||
* what each function does and what kinds of objects it applies
|
* 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>
|
template<class RET>
|
||||||
static RET do_with_oh(
|
static RET do_with_oh(
|
||||||
qpdf_data qpdf, qpdf_oh 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)
|
QPDF_BOOL qpdf_oh_is_initialized(qpdf_data qpdf, qpdf_oh oh)
|
||||||
{
|
{
|
||||||
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_initialized");
|
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
|
static QPDFObjectHandle
|
||||||
qpdf_oh_item_internal(qpdf_data qpdf, qpdf_oh item)
|
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.
|
C API. This allows you to clone an object handle.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</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>
|
</itemizedlist>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
@ -881,6 +881,56 @@ static void test31(char const* infile,
|
|||||||
report_errors();
|
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[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
char* p = 0;
|
char* p = 0;
|
||||||
@ -952,6 +1002,8 @@ int main(int argc, char* argv[])
|
|||||||
(n == 29) ? test29 :
|
(n == 29) ? test29 :
|
||||||
(n == 30) ? test30 :
|
(n == 30) ? test30 :
|
||||||
(n == 31) ? test31 :
|
(n == 31) ? test31 :
|
||||||
|
(n == 32) ? test32 :
|
||||||
|
(n == 33) ? test33 :
|
||||||
0);
|
0);
|
||||||
|
|
||||||
if (fn == 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 warn about oh error 1
|
||||||
qpdf-c registered oh error handler 0
|
qpdf-c registered oh error handler 0
|
||||||
qpdf-c cleanup warned about unhandled error 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();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
$td->notify("--- C API Object Handle ---");
|
$td->notify("--- C API Object Handle ---");
|
||||||
$n_tests += 10;
|
$n_tests += 13;
|
||||||
|
|
||||||
$td->runtest("C check object handles",
|
$td->runtest("C check object handles",
|
||||||
{$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"},
|
{$td->COMMAND => "qpdf-ctest 24 minimal.pdf '' a.pdf"},
|
||||||
@ -4831,6 +4831,14 @@ $td->runtest("check output",
|
|||||||
{$td->FILE => 'a.pdf'},
|
{$td->FILE => 'a.pdf'},
|
||||||
{$td->FILE => 'c-object-handle-creation-out.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->runtest("C uninitialized objects",
|
||||||
{$td->COMMAND => "qpdf-ctest 26 '' '' ''"},
|
{$td->COMMAND => "qpdf-ctest 26 '' '' ''"},
|
||||||
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
{$td->STRING => "", $td->EXIT_STATUS => 0},
|
||||||
@ -4855,6 +4863,10 @@ $td->runtest("C type mismatch warning",
|
|||||||
{$td->COMMAND => "qpdf-ctest 31 minimal.pdf '' ''"},
|
{$td->COMMAND => "qpdf-ctest 31 minimal.pdf '' ''"},
|
||||||
{$td->FILE => "c-type-warning.out", $td->EXIT_STATUS => 0},
|
{$td->FILE => "c-type-warning.out", $td->EXIT_STATUS => 0},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$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();
|
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