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
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
// 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_DLL
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
enum qpdf_object_type_e qpdf_oh_get_type_code(qpdf_data qpdf, qpdf_oh oh);
QPDF_DLL

View File

@ -497,6 +497,34 @@ QPDFObjectHandle::isScalar()
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

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)
{
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_unparse_binary(qpdf, p_string), "<33f7>") == 0));
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(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_name_and_equals(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_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_get_type_code(qpdf, p_null) == ot_null);
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_insert_item(
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);
assert(qpdf_oh_has_key(qpdf, new_dict, "/A"));
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_replace_or_remove_key(
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_indirect 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_name 0
qpdf-c array to wrap_in_array 0

View File

@ -1913,7 +1913,7 @@ $td->runtest("progress report on small file",
show_ntests();
# ----------
$td->notify("--- Type checks ---");
$n_tests += 4;
$n_tests += 5;
# Whenever object-types.pdf is edited, object-types-os.pdf should be
# regenerated.
$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->EXIT_STATUS => 0},
$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 ---");

View File

@ -18,6 +18,8 @@
]
/C <<
>>
/Subtype /Marvin
/Type /Test
>>
/Type /Catalog
>>
@ -93,17 +95,17 @@ xref
0 8
0000000000 65535 f
0000000025 00000 n
0000000240 00000 n
0000000322 00000 n
0000000537 00000 n
0000000636 00000 n
0000000655 00000 n
0000000773 00000 n
0000000277 00000 n
0000000359 00000 n
0000000574 00000 n
0000000673 00000 n
0000000692 00000 n
0000000810 00000 n
trailer <<
/Root 1 0 R
/Size 8
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>>
startxref
808
845
%%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)
{
// 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},
{72, test_72}, {73, test_73}, {74, test_74}, {75, test_75},
{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);