From e7e24fe0706f40b76058bb4b2b46c0307cb6255d Mon Sep 17 00:00:00 2001 From: m-holger Date: Thu, 5 Jan 2023 12:56:34 +0000 Subject: Tidy QPDFAcroFormDocumentHelper::addAndRenameFormFields --- libqpdf/QPDFAcroFormDocumentHelper.cc | 83 ++++++++++++++++------------------- 1 file changed, 39 insertions(+), 44 deletions(-) (limited to 'libqpdf/QPDFAcroFormDocumentHelper.cc') diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index 70e1b9c9..8c2c5e56 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -68,53 +68,48 @@ QPDFAcroFormDocumentHelper::addAndRenameFormFields( { analyze(); std::map renames; - std::list queue; - queue.insert(queue.begin(), fields.begin(), fields.end()); - std::set seen; - while (!queue.empty()) { - QPDFObjectHandle obj = queue.front(); - queue.pop_front(); - auto og = obj.getObjGen(); - if (seen.count(og)) { - // loop - continue; - } - seen.insert(og); - auto kids = obj.getKey("/Kids"); - if (kids.isArray()) { - for (auto kid: kids.aitems()) { - queue.push_back(kid); + QPDFObjGen::set seen; + for (std::list queue{fields.begin(), fields.end()}; + !queue.empty(); + queue.pop_front()) { + auto& obj = queue.front(); + if (seen.add(obj)) { + auto kids = obj.getKey("/Kids"); + if (kids.isArray()) { + for (auto kid: kids.aitems()) { + queue.push_back(kid); + } } - } - if (obj.hasKey("/T")) { - // Find something we can append to the partial name that - // makes the fully qualified name unique. When we find - // something, reuse the same suffix for all fields in this - // group with the same name. We can only change the name - // of fields that have /T, and this field's /T is always - // at the end of the fully qualified name, appending to /T - // has the effect of appending the same thing to the fully - // qualified name. - std::string old_name = - QPDFFormFieldObjectHelper(obj).getFullyQualifiedName(); - if (renames.count(old_name) == 0) { - std::string new_name = old_name; - int suffix = 0; - std::string append; - while (!getFieldsWithQualifiedName(new_name).empty()) { - ++suffix; - append = "+" + std::to_string(suffix); - new_name = old_name + append; + if (obj.hasKey("/T")) { + // Find something we can append to the partial name that + // makes the fully qualified name unique. When we find + // something, reuse the same suffix for all fields in this + // group with the same name. We can only change the name + // of fields that have /T, and this field's /T is always + // at the end of the fully qualified name, appending to /T + // has the effect of appending the same thing to the fully + // qualified name. + std::string old_name = + QPDFFormFieldObjectHelper(obj).getFullyQualifiedName(); + if (renames.count(old_name) == 0) { + std::string new_name = old_name; + int suffix = 0; + std::string append; + while (!getFieldsWithQualifiedName(new_name).empty()) { + ++suffix; + append = "+" + std::to_string(suffix); + new_name = old_name + append; + } + renames[old_name] = append; + } + std::string append = renames[old_name]; + if (!append.empty()) { + obj.replaceKey( + "/T", + QPDFObjectHandle::newUnicodeString( + obj.getKey("/T").getUTF8Value() + append)); } - renames[old_name] = append; - } - std::string append = renames[old_name]; - if (!append.empty()) { - obj.replaceKey( - "/T", - QPDFObjectHandle::newUnicodeString( - obj.getKey("/T").getUTF8Value() + append)); } } } -- cgit v1.2.3-54-g00ecf From c12a6d06fcd7990ff42fa6285185a4692c209ec5 Mon Sep 17 00:00:00 2001 From: m-holger Date: Thu, 5 Jan 2023 13:10:27 +0000 Subject: Use QPDFObjGen::set in QPDFAcroFormDocumentHelper::traverseField --- include/qpdf/QPDFAcroFormDocumentHelper.hh | 2 +- libqpdf/QPDFAcroFormDocumentHelper.cc | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'libqpdf/QPDFAcroFormDocumentHelper.cc') diff --git a/include/qpdf/QPDFAcroFormDocumentHelper.hh b/include/qpdf/QPDFAcroFormDocumentHelper.hh index 4539b52d..d1ac6253 100644 --- a/include/qpdf/QPDFAcroFormDocumentHelper.hh +++ b/include/qpdf/QPDFAcroFormDocumentHelper.hh @@ -254,7 +254,7 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper QPDFObjectHandle field, QPDFObjectHandle parent, int depth, - std::set& visited); + QPDFObjGen::set& visited); QPDFObjectHandle getOrCreateAcroForm(); void adjustInheritedFields( QPDFObjectHandle obj, diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index 8c2c5e56..c44f7838 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -57,7 +57,7 @@ QPDFAcroFormDocumentHelper::addFormField(QPDFFormFieldObjectHelper ff) "/Fields", QPDFObjectHandle::newArray()); } fields.appendItem(ff.getObjectHandle()); - std::set visited; + QPDFObjGen::set visited; traverseField( ff.getObjectHandle(), QPDFObjectHandle::newNull(), 0, visited); } @@ -167,7 +167,7 @@ QPDFAcroFormDocumentHelper::setFormFieldName( QPDFFormFieldObjectHelper ff, std::string const& name) { ff.setFieldAttribute("/T", name); - std::set visited; + QPDFObjGen::set visited; auto ff_oh = ff.getObjectHandle(); traverseField(ff_oh, ff_oh.getKey("/Parent"), 0, visited); } @@ -273,7 +273,7 @@ QPDFAcroFormDocumentHelper::analyze() // Traverse /AcroForm to find annotations and map them // bidirectionally to fields. - std::set visited; + QPDFObjGen::set visited; int nfields = fields.getArrayNItems(); QPDFObjectHandle null(QPDFObjectHandle::newNull()); for (int i = 0; i < nfields; ++i) { @@ -319,7 +319,7 @@ QPDFAcroFormDocumentHelper::traverseField( QPDFObjectHandle field, QPDFObjectHandle parent, int depth, - std::set& visited) + QPDFObjGen::set& visited) { if (depth > 100) { // Arbitrarily cut off recursion at a fixed depth to avoid @@ -341,12 +341,11 @@ QPDFAcroFormDocumentHelper::traverseField( return; } QPDFObjGen og(field.getObjGen()); - if (visited.count(og) != 0) { + if (!visited.add(og)) { QTC::TC("qpdf", "QPDFAcroFormDocumentHelper loop"); field.warnIfPossible("loop detected while traversing /AcroForm"); return; } - visited.insert(og); // A dictionary encountered while traversing the /AcroForm field // may be a form field, an annotation, or the merger of the two. A -- cgit v1.2.3-54-g00ecf From e37ce44186b74d88551d1e8814141776cd15463e Mon Sep 17 00:00:00 2001 From: m-holger Date: Thu, 5 Jan 2023 14:04:41 +0000 Subject: Use QPDFObjGen::set in QPDFAcroFormDocumentHelper::transformAnnotations --- libqpdf/QPDFAcroFormDocumentHelper.cc | 118 ++++++++++++++++------------------ 1 file changed, 56 insertions(+), 62 deletions(-) (limited to 'libqpdf/QPDFAcroFormDocumentHelper.cc') diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index c44f7838..f8ccddf0 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -882,7 +882,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( // Now do the actual copies. - std::set added_new_fields; + QPDFObjGen::set added_new_fields; for (auto annot: old_annots.aitems()) { if (annot.isStream()) { annot.warnIfPossible("ignoring annotation that's a stream"); @@ -964,73 +964,68 @@ QPDFAcroFormDocumentHelper::transformAnnotations( // Traverse the field, copying kids, and preserving // integrity. std::list queue; + QPDFObjGen::set seen; if (maybe_copy_object(top_field)) { queue.push_back(top_field); } - std::set seen; - while (!queue.empty()) { - QPDFObjectHandle obj = queue.front(); - queue.pop_front(); - auto orig_og = obj.getObjGen(); - if (seen.count(orig_og)) { - // loop - break; - } - seen.insert(orig_og); - auto parent = obj.getKey("/Parent"); - if (parent.isIndirect()) { - auto parent_og = parent.getObjGen(); - if (orig_to_copy.count(parent_og)) { - obj.replaceKey("/Parent", orig_to_copy[parent_og]); - } else { - parent.warnIfPossible( - "while traversing field " + - obj.getObjGen().unparse(',') + ", found parent (" + - parent_og.unparse(',') + - ") that had not been seen, indicating likely" - " invalid field structure"); + for (; !queue.empty(); queue.pop_front()) { + auto& obj = queue.front(); + if (seen.add(obj)) { + auto parent = obj.getKey("/Parent"); + if (parent.isIndirect()) { + auto parent_og = parent.getObjGen(); + if (orig_to_copy.count(parent_og)) { + obj.replaceKey("/Parent", orig_to_copy[parent_og]); + } else { + parent.warnIfPossible( + "while traversing field " + + obj.getObjGen().unparse(',') + + ", found parent (" + parent_og.unparse(',') + + ") that had not been seen, indicating likely" + " invalid field structure"); + } } - } - auto kids = obj.getKey("/Kids"); - if (kids.isArray()) { - for (int i = 0; i < kids.getArrayNItems(); ++i) { - auto kid = kids.getArrayItem(i); - if (maybe_copy_object(kid)) { - kids.setArrayItem(i, kid); - queue.push_back(kid); + auto kids = obj.getKey("/Kids"); + if (kids.isArray()) { + for (int i = 0; i < kids.getArrayNItems(); ++i) { + auto kid = kids.getArrayItem(i); + if (maybe_copy_object(kid)) { + kids.setArrayItem(i, kid); + queue.push_back(kid); + } } } - } - if (override_da || override_q) { - adjustInheritedFields( - obj, - override_da, - from_default_da, - override_q, - from_default_q); - } - if (foreign) { - // Lazily initialize our /DR and the conflict map. - init_dr_map(); - // The spec doesn't say anything about /DR on the - // field, but lots of writers put one there, and - // it is frequently the same as the document-level - // /DR. To avoid having the field's /DR point to - // information that we are not maintaining, just - // reset it to that if it exists. Empirical - // evidence suggests that many readers, including - // Acrobat, Adobe Acrobat Reader, chrome, firefox, - // the mac Preview application, and several of the - // free readers on Linux all ignore /DR at the - // field level. - if (obj.hasKey("/DR")) { - obj.replaceKey("/DR", dr); + if (override_da || override_q) { + adjustInheritedFields( + obj, + override_da, + from_default_da, + override_q, + from_default_q); + } + if (foreign) { + // Lazily initialize our /DR and the conflict map. + init_dr_map(); + // The spec doesn't say anything about /DR on the + // field, but lots of writers put one there, and + // it is frequently the same as the document-level + // /DR. To avoid having the field's /DR point to + // information that we are not maintaining, just + // reset it to that if it exists. Empirical + // evidence suggests that many readers, including + // Acrobat, Adobe Acrobat Reader, chrome, firefox, + // the mac Preview application, and several of the + // free readers on Linux all ignore /DR at the + // field level. + if (obj.hasKey("/DR")) { + obj.replaceKey("/DR", dr); + } + } + if (foreign && obj.getKey("/DA").isString() && + (!dr_map.empty())) { + adjustDefaultAppearances(obj, dr_map); } - } - if (foreign && obj.getKey("/DA").isString() && - (!dr_map.empty())) { - adjustDefaultAppearances(obj, dr_map); } } @@ -1058,9 +1053,8 @@ QPDFAcroFormDocumentHelper::transformAnnotations( maybe_copy_object(annot); // Now we have copies, so we can safely mutate. - if (have_field && !added_new_fields.count(top_field.getObjGen())) { + if (have_field && added_new_fields.add(top_field)) { new_fields.push_back(top_field); - added_new_fields.insert(top_field.getObjGen()); } new_annots.push_back(annot); -- cgit v1.2.3-54-g00ecf From 5b3b135fda353379a508088a9931ebb24b68d53d Mon Sep 17 00:00:00 2001 From: m-holger Date: Thu, 5 Jan 2023 14:44:16 +0000 Subject: Tidy QPDFAcroFormDocumentHelper::getFieldsWithQualifiedName --- libqpdf/QPDFAcroFormDocumentHelper.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'libqpdf/QPDFAcroFormDocumentHelper.cc') diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index f8ccddf0..6a7eca55 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -188,12 +188,11 @@ QPDFAcroFormDocumentHelper::getFieldsWithQualifiedName(std::string const& name) { analyze(); // Keep from creating an empty entry - std::set result; auto iter = this->m->name_to_fields.find(name); if (iter != this->m->name_to_fields.end()) { - result = iter->second; + return iter->second; } - return result; + return {}; } std::vector -- cgit v1.2.3-54-g00ecf From d395a90904f6f30fdf76dae0eb5219c1c832813c Mon Sep 17 00:00:00 2001 From: m-holger Date: Thu, 5 Jan 2023 14:51:54 +0000 Subject: Use QPDFObjGen::set in QPDFAcroFormDocumentHelper::getFormFieldsForPage --- libqpdf/QPDFAcroFormDocumentHelper.cc | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'libqpdf/QPDFAcroFormDocumentHelper.cc') diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index 6a7eca55..9c59055e 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -217,18 +217,12 @@ std::vector QPDFAcroFormDocumentHelper::getFormFieldsForPage(QPDFPageObjectHelper ph) { analyze(); - std::set added; + QPDFObjGen::set todo; std::vector result; - auto widget_annotations = getWidgetAnnotationsForPage(ph); - for (auto annot: widget_annotations) { - auto field = getFieldForAnnotation(annot); - field = field.getTopLevelField(); - auto og = field.getObjectHandle().getObjGen(); - if (!added.count(og)) { - added.insert(og); - if (field.getObjectHandle().isDictionary()) { - result.push_back(field); - } + for (auto& annot: getWidgetAnnotationsForPage(ph)) { + auto field = getFieldForAnnotation(annot).getTopLevelField(); + if (todo.add(field) && field.getObjectHandle().isDictionary()) { + result.push_back(field); } } return result; -- cgit v1.2.3-54-g00ecf