aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorm-holger <m-holger@kubitscheck.org>2022-01-21 15:09:06 +0100
committerJay Berkenbilt <jberkenbilt@users.noreply.github.com>2022-01-22 15:10:28 +0100
commit8593b9fdf74e68099a5fe2aa0b6d0b6320781a2d (patch)
treee280ab8d4af58b16f21a4e3fb05342c04e0e3d29
parent370710657a7e7c771668107d1b6407fc350a2891 (diff)
downloadqpdf-8593b9fdf74e68099a5fe2aa0b6d0b6320781a2d.tar.zst
Add new convenience methods QPDFObjectHandle::isNameAndEquals, etc
Add methods isNameAndEquals, isDictionaryOfType, isStreamOfType
-rw-r--r--include/qpdf/QPDFObjectHandle.hh16
-rw-r--r--include/qpdf/qpdf-c.h9
-rw-r--r--libqpdf/QPDFObjectHandle.cc28
-rw-r--r--libqpdf/qpdf-c.cc21
-rw-r--r--qpdf/qpdf-ctest.c13
-rw-r--r--qpdf/qpdf.testcov2
-rw-r--r--qpdf/qtest/qpdf.test6
-rw-r--r--qpdf/qtest/qpdf/c-object-handle-creation-out.pdf16
-rw-r--r--qpdf/test_driver.cc35
9 files changed, 136 insertions, 10 deletions
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index ccc3993e..f540272d 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -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
diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h
index 7369e616..b62f2e09 100644
--- a/include/qpdf/qpdf-c.h
+++ b/include/qpdf/qpdf-c.h
@@ -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
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 1a8e3223..f2c77dca 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -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
diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc
index fb79407d..44950568 100644
--- a/libqpdf/qpdf-c.cc
+++ b/libqpdf/qpdf-c.cc
@@ -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>(
diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c
index af743b01..13144fe3 100644
--- a/qpdf/qpdf-ctest.c
+++ b/qpdf/qpdf-ctest.c
@@ -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));
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index 35417d4c..d900b3d6 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -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
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 5f61388b..7dce31ed 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -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 ---");
diff --git a/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf b/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf
index 400ebf0d..729feb0d 100644
--- a/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf
+++ b/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf
@@ -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
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index f01c31db..802948cc 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -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);