From 8cb245739c76a1766473174500275d5d8b215d98 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Fri, 25 Jan 2019 18:15:23 -0500 Subject: [PATCH] Add QPDFObjectHandle::getUniqueResourceName --- ChangeLog | 4 ++++ include/qpdf/QPDFObjectHandle.hh | 12 ++++++++++++ libqpdf/QPDFObjectHandle.cc | 24 ++++++++++++++++++++++++ libqpdf/QPDFPageDocumentHelper.cc | 26 +++----------------------- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index c04b2333..5e327abc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2019-01-25 Jay Berkenbilt + * Add new method QPDFObjectHandle::getUniqueResourceName() to + return an unused key available to be used in a resource + dictionary. + * Add new method QPDFPageObjectHelper::getAttribute() that properly handles inherited attributes and allows for creation of a copy of shared attributes. This is very useful if you are getting diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index d6bb1a3b..b181bd79 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -600,6 +600,18 @@ class QPDFObjectHandle QPDF_DLL std::set getResourceNames(); + // Find a unique name within a resource dictionary starting with a + // given prefix. This method works by appending a number to the + // given prefix. It searches starting with min_suffix and sets + // min_suffix to selected value upon return. This can be used to + // increase efficiency if adding multiple items with the same + // prefix. (Why doesn't it set min_suffix to the next number? + // Well, maybe you aren't going to actually use the name it + // returns.) + QPDF_DLL + std::string getUniqueResourceName(std::string const& prefix, + int& min_suffix); + // Return the QPDF object that owns an indirect object. Returns // null for a direct object. QPDF_DLL diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index b802a55c..4e77bbaa 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -931,6 +931,30 @@ QPDFObjectHandle::getResourceNames() return result; } +std::string +QPDFObjectHandle::getUniqueResourceName(std::string const& prefix, + int& min_suffix) +{ + std::set names = getResourceNames(); + int max_suffix = min_suffix + names.size(); + while (min_suffix <= max_suffix) + { + std::string candidate = prefix + QUtil::int_to_string(min_suffix); + if (names.count(candidate) == 0) + { + return candidate; + } + // Increment after return; min_suffix should be the value + // used, not the next value. + ++min_suffix; + } + // This could only happen if there is a coding error. + // The number of candidates we test is more than the + // number of keys we're checking against. + throw std::logic_error("unable to find unconflicting name in" + " QPDFObjectHandle::getUniqueResourceName"); +} + // Indirect object accessors QPDF* QPDFObjectHandle::getOwningQPDF() diff --git a/libqpdf/QPDFPageDocumentHelper.cc b/libqpdf/QPDFPageDocumentHelper.cc index 3eec789b..58d6ed22 100644 --- a/libqpdf/QPDFPageDocumentHelper.cc +++ b/libqpdf/QPDFPageDocumentHelper.cc @@ -155,35 +155,15 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage( { QTC::TC("qpdf", "QPDFPageDocumentHelper non-widget annotation"); } - std::set names = resources.getResourceNames(); - std::string name; - int max_fx = next_fx + names.size() + 1; - while (next_fx <= max_fx) - { - std::string candidate = "/Fxo" + QUtil::int_to_string(next_fx); - if (names.count(candidate) == 0) - { - name = candidate; - break; - } - ++next_fx; - } - if (name.empty()) - { - // This could only happen if there is a coding error. - // The number of candidates we test is more than the - // number of keys we're checking against. - name = "/FxConflict"; - } + std::string name = resources.getUniqueResourceName( + "/Fxo", next_fx); std::string content = aoh.getPageContentForAppearance( name, rotate, required_flags, forbidden_flags); if (! content.empty()) { resources.mergeResources( - QPDFObjectHandle::parse( - "<< /XObject << " + name + " null >> >>")); + QPDFObjectHandle::parse("<< /XObject << >> >>")); resources.getKey("/XObject").replaceKey(name, as); - names.insert(name); ++next_fx; } new_content += content;