FormField.hh
14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
#ifndef FORMFIELD_HH
#define FORMFIELD_HH
#include <qpdf/QPDFObjectHandle_private.hh>
#include <qpdf/QPDFObjectHelper.hh>
#include <vector>
class QPDFAnnotationObjectHelper;
namespace qpdf::impl
{
// This object helper helps with form fields for interactive forms. Please see comments in
// QPDFAcroFormDocumentHelper.hh for additional details.
class FormField: public qpdf::BaseDictionary
{
public:
FormField() = default;
FormField(FormField const&) = default;
FormField& operator=(FormField const&) = default;
FormField(FormField&&) = default;
FormField& operator=(FormField&&) = default;
~FormField() = default;
FormField(QPDFObjectHandle const& oh) :
BaseDictionary(oh)
{
}
FormField(QPDFObjectHandle&& oh) :
BaseDictionary(std::move(oh))
{
}
/// Retrieves the /Parent form field of the current field.
///
/// This function accesses the parent field in the hierarchical structure of form fields, if
/// it exists. The parent is determined based on the /Parent attribute in the field
/// dictionary.
///
/// @return A FormField object representing the parent field. If the current field has no
/// parent, an empty FormField object is returned.
FormField
Parent()
{
return {get("/Parent")};
}
/// @brief Returns the top-level field associated with the current field.
///
/// The function traverses the hierarchy of parent fields to identify the highest-level
/// field in the tree. Typically, this will be the current field itself unless it has a
/// parent field. Optionally, it can indicate whether the top-level field is different from
/// the current field.
///
/// @param is_different A pointer to a boolean that, if provided, will be set to true if the
/// top-level field differs from the current field; otherwise, it will be set to
/// false.
///
/// @return The top-level field in the form field hierarchy.
FormField root_field(bool* is_different = nullptr);
/// @brief Retrieves the inherited value of the specified attribute.
///
/// @param name The name of the attribute to retrieve.
/// @param acroform If true, checks the document's /AcroForm dictionary for the attribute
/// if it is not found in the field hierarchy.
///
/// @return A constant reference to the QPDFObjectHandle representing the value of the
/// specified attribute, if found. If the attribute is not found in the field
/// hierarchy or the /AcroForm dictionary (when `acroform` is true), returns a
/// reference to a static null object handle.
QPDFObjectHandle const& inherited(std::string const& name, bool acroform = false) const;
/// @brief Retrieves the value of a specified field, accounting for inheritance through the
/// hierarchy of ancestor nodes in the form field tree.
///
/// This function attempts to retrieve the value of the specified field. If the `inherit`
/// parameter is set to `true` and the field value is not found at the current level, the
/// method traverses up the parent hierarchy to find the value. The traversal stops when a
/// value is found, when the root node is reached, or when a loop detection mechanism
/// prevents further traversal.
///
/// @tparam T The return type of the field value.
/// @param name The name of the field to retrieve the value for.
/// @param inherit If set to `true`, the function will attempt to retrieve the value by
/// inheritance from the parent hierarchy of the form field. Defaults to `true`.
/// @return Returns the field's value if found; otherwise, returns a default-constructed
/// value of type `T`.
template <class T>
T
inheritable_value(std::string const& name, bool inherit = true, bool acroform = false) const
{
if (auto& v = get(name)) {
return {v};
}
return {inherit ? inherited(name, acroform) : null_oh};
}
/// @brief Retrieves an inherited field string attribute as a string.
///
/// @param name The name of the field for which the value is to be retrieved.
/// @return The inherited field value as a UTF-8 encoded string, or an empty string if the
/// value does not exist or is not of String type.
std::string inheritable_string(std::string const& name) const;
/// @brief Retrieves the field type (/FT attribute).
///
/// @param inherit If set to `true`, the function will attempt to retrieve the value by
/// inheritance from the parent hierarchy of the form field. Defaults to `true`.
/// @return Returns the field type if found; otherwise, returns a default-constructed
/// `Name`.
Name
FT(bool inherit = true) const
{
return inheritable_value<Name>("/FT");
}
/// @brief Retrieves the partial field name (/T attribute).
///
/// @return Returns the partial field name if found; otherwise, returns a
/// default-constructed `String`.
String
T() const
{
return {get("/T")};
}
/// @brief Retrieves the alternative name (/TU attribute).
///
/// @return Returns the alternative name if found; otherwise, returns a default-constructed
/// `String`.
String
TU() const
{
return {get("/TU")};
}
/// @brief Retrieves the mapping name (/TM attribute).
///
/// @return Returns the mapping name if found; otherwise, returns a default-constructed
/// `String`.
String
TM() const
{
return {get("/TM")};
}
/// @brief Retrieves the fully qualified name of the form field.
///
/// This method constructs the fully qualified name of the form field by traversing through
/// its parent hierarchy. The fully qualified name is constructed by concatenating the /T
/// (field name) attribute of each parent node with periods as separators, starting from the
/// root of the hierarchy.
///
/// If the field has no parent hierarchy, the result will simply be the /T attribute of the
/// current field. In cases of potential circular references, loop detection is applied.
///
/// @return A string representing the fully qualified name of the field.
std::string fully_qualified_name() const;
/// @brief Retrieves the partial name (/T attribute) of the form field.
///
/// This method returns the value of the field's /T attribute, which is the partial name
/// used to identify the field within its parent hierarchy. If the attribute is not set, an
/// empty string is returned.
///
/// @return A string representing the partial name of the field in UTF-8 encoding, or an
/// empty string if the /T attribute is not present.
std::string partial_name() const;
/// @brief Retrieves the alternative name for the form field.
///
/// This method attempts to return the alternative name (/TU) of the form field, which is
/// the field name intended to be presented, to users as a UTF-8 string, if it exists. If
/// the alternative name is not present, the method falls back to the fully qualified name
/// of the form field.
///
/// @return The alternative name of the form field as a string, or the
/// fully qualified name if the alternative name is unavailable.
std::string alternative_name() const;
/// @brief Retrieves the mapping field name (/TM) for the form field.
///
/// If the mapping name (/TM) is present, it is returned as a UTF-8 string. If not, it falls
/// back to the 'alternative name', which is obtained using the `alternative_name()` method.
///
/// @return The mapping field name (/TM) as a UTF-8 string or the alternative name
/// if the mapping name is absent.
std::string mapping_name() const;
QPDFObjectHandle getValue();
// Return the field's value as a string. If this is called with a field whose value is not a
std::string getValueAsString();
QPDFObjectHandle getDefaultValue();
// Return the field's default value as a string. If this is called with a field whose value
// is not a string, the empty string will be silently returned.
std::string getDefaultValueAsString();
// Return the default appearance string, taking inheritance from the field tree into
// account. Returns the empty string if the default appearance string is not available
// (because it's erroneously absent or because this is not a variable text field). If not
// found in the field hierarchy, look in /AcroForm.
std::string getDefaultAppearance();
// Return the default resource dictionary for the field. This comes not from the field but
// from the document-level /AcroForm dictionary. While several PDF generates put a /DR key
// in the form field's dictionary, experimentation suggests that many popular readers,
// including Adobe Acrobat and Acrobat Reader, ignore any /DR item on the field.
QPDFObjectHandle getDefaultResources();
// Return the quadding value, taking inheritance from the field tree into account. Returns 0
// if quadding is not specified. Look in /AcroForm if not found in the field hierarchy.
int getQuadding();
// Return field flags from /Ff. The value is a logical or of pdf_form_field_flag_e as
// defined in qpdf/Constants.h//
int getFlags();
// Methods for testing for particular types of form fields
// Returns true if field is of type /Tx
bool isText();
// Returns true if field is of type /Btn and flags do not indicate some other type of
// button.
bool isCheckbox();
// Returns true if field is a checkbox and is checked.
bool isChecked();
// Returns true if field is of type /Btn and flags indicate that it is a radio button
bool isRadioButton();
// Returns true if field is of type /Btn and flags indicate that it is a pushbutton
bool isPushbutton();
// Returns true if fields if of type /Ch
bool isChoice();
// Returns choices display values as UTF-8 strings
std::vector<std::string> getChoices();
// Set an attribute to the given value. If you have a QPDFAcroFormDocumentHelper and you
// want to set the name of a field, use QPDFAcroFormDocumentHelper::setFormFieldName
// instead.
void setFieldAttribute(std::string const& key, QPDFObjectHandle value);
// Set an attribute to the given value as a Unicode string (UTF-16 BE encoded). The input
// string should be UTF-8 encoded. If you have a QPDFAcroFormDocumentHelper and you want to
// set the name of a field, use QPDFAcroFormDocumentHelper::setFormFieldName instead.
void setFieldAttribute(std::string const& key, std::string const& utf8_value);
// Set /V (field value) to the given value. If need_appearances is true and the field type
// is either /Tx (text) or /Ch (choice), set /NeedAppearances to true. You can explicitly
// tell this method not to set /NeedAppearances if you are going to generate an appearance
// stream yourself. Starting with qpdf 8.3.0, this method handles fields of type /Btn
// (checkboxes, radio buttons, pushbuttons) specially. When setting a checkbox value, any
// value other than /Off will be treated as on, and the actual value set will be based on
// the appearance stream's /N dictionary, so the value that ends up in /V may not exactly
// match the value you pass in.
void setV(QPDFObjectHandle value, bool need_appearances = true);
// Set /V (field value) to the given string value encoded as a Unicode string. The input
// value should be UTF-8 encoded. See comments above about /NeedAppearances.
void setV(std::string const& utf8_value, bool need_appearances = true);
// Update the appearance stream for this field. Note that qpdf's ability to generate
// appearance streams is limited. We only generate appearance streams for streams of type
// text or choice. The appearance uses the default parameters provided in the file, and it
// only supports ASCII characters. Quadding is currently ignored. While this functionality
// is limited, it should do a decent job on properly constructed PDF files when field values
// are restricted to ASCII characters.
void generateAppearance(QPDFAnnotationObjectHelper&);
private:
/// @brief Retrieves an entry from the document's /AcroForm dictionary using the specified
/// name.
///
/// The method accesses the AcroForm dictionary within the root object of the PDF document.
/// If the the AcroForm dictionary contains the given field name, it retrieves the
/// corresponding entry. Otherwise, it returns a default-constructed object handle.
///
/// @param name The name of the form field to retrieve.
/// @return A object handle corresponding to the specified name within the AcroForm
/// dictionary.
QPDFObjectHandle const&
from_AcroForm(std::string const& name) const
{
return {qpdf() ? qpdf()->getRoot()["/AcroForm"][name] : null_oh};
}
void setRadioButtonValue(QPDFObjectHandle name);
void setCheckBoxValue(bool value);
void generateTextAppearance(QPDFAnnotationObjectHelper&);
QPDFObjectHandle
getFontFromResource(QPDFObjectHandle resources, std::string const& font_name);
static const QPDFObjectHandle null_oh;
};
} // namespace qpdf::impl
#endif // FORMFIELD_HH