2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-09-22 18:19:08 +00:00

Add new convenience methods QPDFObjectHandle::isNameAndEquals, etc

Add methods isNameAndEquals, isDictionaryOfType, isStreamOfType
This commit is contained in:
m-holger 2022-01-21 14:09:06 +00:00 committed by Jay Berkenbilt
parent 370710657a
commit 8593b9fdf7
9 changed files with 136 additions and 10 deletions

View File

@ -365,6 +365,22 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
bool isScalar(); bool isScalar();
// True if the object is a name object representing the provided name.
QPDF_DLL
bool isNameAndEquals(std::string const& name);
// True if the object is a dictionary of the specified type and
// subtype, if any.
QPDF_DLL
bool isDictionaryOfType(std::string const& type,
std::string const& subtype = "");
// True if the object is a stream of the specified type and
// subtype, if any.
QPDF_DLL
bool isStreamOfType(std::string const& type,
std::string const& subtype = "");
// Public factory methods // Public factory methods
// Wrap an object in an array if it is not already an array. This // Wrap an object in an array if it is not already an array. This

View File

@ -676,6 +676,15 @@ extern "C" {
QPDF_BOOL qpdf_oh_is_indirect(qpdf_data qpdf, qpdf_oh oh); QPDF_BOOL qpdf_oh_is_indirect(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL
QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh); QPDF_BOOL qpdf_oh_is_scalar(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL
QPDF_BOOL qpdf_oh_is_name_and_equals(
qpdf_data qpdf, qpdf_oh oh, char const* name);
QPDF_DLL
QPDF_BOOL qpdf_oh_is_dictionary_of_type(
qpdf_data qpdf, qpdf_oh oh, char const* type, char const* subtype);
QPDF_DLL QPDF_DLL
enum qpdf_object_type_e qpdf_oh_get_type_code(qpdf_data qpdf, qpdf_oh oh); enum qpdf_object_type_e qpdf_oh_get_type_code(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL QPDF_DLL

View File

@ -497,6 +497,34 @@ QPDFObjectHandle::isScalar()
isOperator() || isInlineImage())); isOperator() || isInlineImage()));
} }
bool
QPDFObjectHandle::isNameAndEquals(std::string const& name)
{
return isName() && (getName() == name);
}
bool
QPDFObjectHandle::isDictionaryOfType(std::string const& type,
std::string const& subtype)
{
if (isDictionary() && getKey("/Type").isNameAndEquals(type))
{
return (subtype == "") ||
(hasKey("/Subtype") && getKey("/Subtype").isNameAndEquals(subtype));
}
else
{
return false;
}
}
bool
QPDFObjectHandle::isStreamOfType(std::string const& type,
std::string const& subtype)
{
return isStream() && getDict().isDictionaryOfType(type, subtype);
}
// Bool accessors // Bool accessors
bool bool

View File

@ -1148,6 +1148,27 @@ QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh)
}); });
} }
QPDF_BOOL qpdf_oh_is_name_and_equals(
qpdf_data qpdf, qpdf_oh oh, char const* name)
{
return do_with_oh<QPDF_BOOL>(
qpdf, oh, return_false, [name](QPDFObjectHandle& o) {
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_name_and_equals");
return o.isNameAndEquals(name);
});
}
QPDF_BOOL qpdf_oh_is_dictionary_of_type(
qpdf_data qpdf, qpdf_oh oh, char const* type, char const* subtype)
{
auto stype = (subtype == nullptr) ? "" : subtype;
return do_with_oh<QPDF_BOOL>(
qpdf, oh, return_false, [type, stype](QPDFObjectHandle& o) {
QTC::TC("qpdf", "qpdf-c called qpdf_oh_is_dictionary_of_type");
return o.isDictionaryOfType(type, stype);
});
}
qpdf_object_type_e qpdf_oh_get_type_code(qpdf_data qpdf, qpdf_oh oh) qpdf_object_type_e qpdf_oh_get_type_code(qpdf_data qpdf, qpdf_oh oh)
{ {
return do_with_oh<qpdf_object_type_e>( return do_with_oh<qpdf_object_type_e>(

View File

@ -694,12 +694,16 @@ static void test25(char const* infile,
(strcmp(qpdf_oh_get_utf8_value(qpdf, p_string), "3\xc3\xb7") == 0) && (strcmp(qpdf_oh_get_utf8_value(qpdf, p_string), "3\xc3\xb7") == 0) &&
(strcmp(qpdf_oh_unparse_binary(qpdf, p_string), "<33f7>") == 0)); (strcmp(qpdf_oh_unparse_binary(qpdf, p_string), "<33f7>") == 0));
assert(qpdf_oh_get_type_code(qpdf, p_string) == ot_string); assert(qpdf_oh_get_type_code(qpdf, p_string) == ot_string);
assert(! qpdf_oh_is_name_and_equals(qpdf, p_string, "3\xf7"));
assert(strcmp(qpdf_oh_get_type_name(qpdf, p_string), "string") == 0); assert(strcmp(qpdf_oh_get_type_name(qpdf, p_string), "string") == 0);
assert(qpdf_oh_is_dictionary(qpdf, p_dict)); assert(qpdf_oh_is_dictionary(qpdf, p_dict));
qpdf_oh p_five = qpdf_oh_get_key(qpdf, p_dict, "/Four"); 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, p_five, "/Five"));
assert(! qpdf_oh_is_name_and_equals(qpdf, p_five, "/Five"));
assert(qpdf_oh_is_or_has_name( assert(qpdf_oh_is_or_has_name(
qpdf, qpdf_oh_get_array_item(qpdf, p_five, 0), "/Five")); qpdf, qpdf_oh_get_array_item(qpdf, p_five, 0), "/Five"));
assert(qpdf_oh_is_name_and_equals(
qpdf, qpdf_oh_get_array_item(qpdf, p_five, 0), "/Five"));
assert(qpdf_oh_is_null(qpdf, p_null)); assert(qpdf_oh_is_null(qpdf, p_null));
assert(qpdf_oh_get_type_code(qpdf, p_null) == ot_null); assert(qpdf_oh_get_type_code(qpdf, p_null) == ot_null);
assert(strcmp(qpdf_oh_get_type_name(qpdf, p_null), "null") == 0); assert(strcmp(qpdf_oh_get_type_name(qpdf, p_null), "null") == 0);
@ -710,10 +714,17 @@ static void test25(char const* infile,
qpdf_oh_erase_item(qpdf, parsed, 4); qpdf_oh_erase_item(qpdf, parsed, 4);
qpdf_oh_insert_item( qpdf_oh_insert_item(
qpdf, parsed, 2, qpdf, parsed, 2,
qpdf_oh_parse(qpdf, "<</A 1 /B 2 /C 3 /D 4>>")); qpdf_oh_parse(
qpdf, "<</A 1 /B 2 /C 3 /D 4 /Type /Test /Subtype /Marvin>>"));
qpdf_oh new_dict = qpdf_oh_get_array_item(qpdf, parsed, 2); 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, "/A"));
assert(qpdf_oh_has_key(qpdf, new_dict, "/D")); assert(qpdf_oh_has_key(qpdf, new_dict, "/D"));
assert(qpdf_oh_is_dictionary_of_type(qpdf, new_dict, "/Test", ""));
assert(qpdf_oh_is_dictionary_of_type(qpdf, new_dict, "/Test", 0));
assert(qpdf_oh_is_dictionary_of_type(qpdf, new_dict, "/Test", "/Marvin"));
assert(! qpdf_oh_is_dictionary_of_type(qpdf, new_dict, "/Test2", ""));
assert(! qpdf_oh_is_dictionary_of_type(qpdf, new_dict, "/Test", "/M"));
assert(! qpdf_oh_is_dictionary_of_type(qpdf, new_dict, "", ""));
qpdf_oh new_array = qpdf_oh_new_array(qpdf); qpdf_oh new_array = qpdf_oh_new_array(qpdf);
qpdf_oh_replace_or_remove_key( qpdf_oh_replace_or_remove_key(
qpdf, new_dict, "/A", qpdf_oh_new_null(qpdf)); qpdf, new_dict, "/A", qpdf_oh_new_null(qpdf));

View File

@ -474,6 +474,8 @@ qpdf-c called qpdf_oh_is_dictionary 0
qpdf-c called qpdf_oh_is_stream 0 qpdf-c called qpdf_oh_is_stream 0
qpdf-c called qpdf_oh_is_indirect 0 qpdf-c called qpdf_oh_is_indirect 0
qpdf-c called qpdf_oh_is_scalar 0 qpdf-c called qpdf_oh_is_scalar 0
qpdf-c called qpdf_oh_is_name_and_equals 0
qpdf-c called qpdf_oh_is_dictionary_of_type 0
qpdf-c called qpdf_oh_get_type_code 0 qpdf-c called qpdf_oh_get_type_code 0
qpdf-c called qpdf_oh_get_type_name 0 qpdf-c called qpdf_oh_get_type_name 0
qpdf-c array to wrap_in_array 0 qpdf-c array to wrap_in_array 0

View File

@ -1913,7 +1913,7 @@ $td->runtest("progress report on small file",
show_ntests(); show_ntests();
# ---------- # ----------
$td->notify("--- Type checks ---"); $td->notify("--- Type checks ---");
$n_tests += 4; $n_tests += 5;
# Whenever object-types.pdf is edited, object-types-os.pdf should be # Whenever object-types.pdf is edited, object-types-os.pdf should be
# regenerated. # regenerated.
$td->runtest("ensure object-types-os is up-to-date", $td->runtest("ensure object-types-os is up-to-date",
@ -1937,6 +1937,10 @@ $td->runtest("type checks with object streams",
{$td->FILE => "object-types-os.out", {$td->FILE => "object-types-os.out",
$td->EXIT_STATUS => 0}, $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES); $td->NORMALIZE_NEWLINES);
$td->runtest("compound type checks",
{$td->COMMAND => "test_driver 82 object-types-os.pdf"},
{$td->STRING => "test 82 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
# ---------- # ----------
$td->notify("--- Coalesce contents ---"); $td->notify("--- Coalesce contents ---");

View File

@ -18,6 +18,8 @@
] ]
/C << /C <<
>> >>
/Subtype /Marvin
/Type /Test
>> >>
/Type /Catalog /Type /Catalog
>> >>
@ -93,17 +95,17 @@ xref
0 8 0 8
0000000000 65535 f 0000000000 65535 f
0000000025 00000 n 0000000025 00000 n
0000000240 00000 n 0000000277 00000 n
0000000322 00000 n 0000000359 00000 n
0000000537 00000 n 0000000574 00000 n
0000000636 00000 n 0000000673 00000 n
0000000655 00000 n 0000000692 00000 n
0000000773 00000 n 0000000810 00000 n
trailer << trailer <<
/Root 1 0 R /Root 1 0 R
/Size 8 /Size 8
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>> >>
startxref startxref
808 845
%%EOF %%EOF

View File

@ -3097,6 +3097,39 @@ static void test_81(QPDF& pdf, char const* arg2)
} }
} }
static void test_82(QPDF& pdf, char const* arg2)
{
// Exercise compound test methods QPDFObjectHandle::isNameAndEquals,
// isDictionaryOfType and isStreamOfType
auto name = QPDFObjectHandle::newName("/Marvin");
auto str = QPDFObjectHandle::newString("/Marvin");
assert(name.isNameAndEquals("/Marvin"));
assert(! name.isNameAndEquals("Marvin"));
assert(! str.isNameAndEquals("/Marvin"));
auto dict = QPDFObjectHandle::parse("<</A 1 /Type /Test /Subtype /Marvin>>");
assert(dict.isDictionaryOfType( "/Test", ""));
assert(dict.isDictionaryOfType("/Test"));
assert(dict.isDictionaryOfType("/Test", "/Marvin"));
assert(! dict.isDictionaryOfType("/Test2", ""));
assert(! dict.isDictionaryOfType("/Test2", "/Marvin"));
assert(! dict.isDictionaryOfType("/Test", "/M"));
assert(! dict.isDictionaryOfType("", "/Marvin"));
assert(! dict.isDictionaryOfType("", ""));
dict = QPDFObjectHandle::parse("<</A 1 /Type null /Subtype /Marvin>>");
assert(! dict.isDictionaryOfType("/Test"));
dict = QPDFObjectHandle::parse("<</A 1 /Type (Test) /Subtype /Marvin>>");
assert(! dict.isDictionaryOfType("Test"));
dict = QPDFObjectHandle::parse("<</A 1 /Type /Test /Subtype (Marvin)>>");
assert(! dict.isDictionaryOfType("Test"));
dict = QPDFObjectHandle::parse("<</A 1 /Subtype /Marvin>>");
assert(! dict.isDictionaryOfType("/Test", "Marvin"));
auto stream = pdf.getObjectByID(1,0);
assert(stream.isStreamOfType("/ObjStm"));
assert(! stream.isStreamOfType("/Test"));
assert(! pdf.getObjectByID(2,0).isStreamOfType("/Pages"));
}
void runtest(int n, char const* filename1, char const* arg2) void runtest(int n, char const* filename1, char const* arg2)
{ {
// Most tests here are crafted to work on specific files. Look at // Most tests here are crafted to work on specific files. Look at
@ -3210,7 +3243,7 @@ void runtest(int n, char const* filename1, char const* arg2)
{68, test_68}, {69, test_69}, {70, test_70}, {71, test_71}, {68, test_68}, {69, test_69}, {70, test_70}, {71, test_71},
{72, test_72}, {73, test_73}, {74, test_74}, {75, test_75}, {72, test_72}, {73, test_73}, {74, test_74}, {75, test_75},
{76, test_76}, {77, test_77}, {78, test_78}, {79, test_79}, {76, test_76}, {77, test_77}, {78, test_78}, {79, test_79},
{80, test_80}, {81, test_81}, {80, test_80}, {81, test_81}, {82, test_82},
}; };
auto fn = test_functions.find(n); auto fn = test_functions.find(n);