1 | #include <QtCore/QCoreApplication> |
2 | #include <QtCore/QDateTime> |
3 | #include <QtCore/QDebug> |
4 | |
5 | #include <iostream> |
6 | |
7 | #include <poppler-qt6.h> |
8 | #include <poppler-form.h> |
9 | |
10 | static std::ostream &operator<<(std::ostream &out, Poppler::FormField::FormType type) |
11 | { |
12 | switch (type) { |
13 | case Poppler::FormField::FormButton: |
14 | out << "Button" ; |
15 | break; |
16 | case Poppler::FormField::FormText: |
17 | out << "Text" ; |
18 | break; |
19 | case Poppler::FormField::FormChoice: |
20 | out << "Choice" ; |
21 | break; |
22 | case Poppler::FormField::FormSignature: |
23 | out << "Signature" ; |
24 | break; |
25 | } |
26 | return out; |
27 | } |
28 | |
29 | static std::ostream &operator<<(std::ostream &out, Poppler::FormFieldButton::ButtonType type) |
30 | { |
31 | switch (type) { |
32 | case Poppler::FormFieldButton::Push: |
33 | out << "Push" ; |
34 | break; |
35 | case Poppler::FormFieldButton::CheckBox: |
36 | out << "CheckBox" ; |
37 | break; |
38 | case Poppler::FormFieldButton::Radio: |
39 | out << "Radio" ; |
40 | break; |
41 | } |
42 | return out; |
43 | } |
44 | |
45 | static std::ostream &operator<<(std::ostream &out, Poppler::FormFieldText::TextType type) |
46 | { |
47 | switch (type) { |
48 | case Poppler::FormFieldText::Normal: |
49 | out << "Normal" ; |
50 | break; |
51 | case Poppler::FormFieldText::Multiline: |
52 | out << "Multiline" ; |
53 | break; |
54 | case Poppler::FormFieldText::FileSelect: |
55 | out << "FileSelect" ; |
56 | break; |
57 | } |
58 | return out; |
59 | } |
60 | |
61 | static std::ostream &operator<<(std::ostream &out, Poppler::FormFieldChoice::ChoiceType type) |
62 | { |
63 | switch (type) { |
64 | case Poppler::FormFieldChoice::ComboBox: |
65 | out << "ComboBox" ; |
66 | break; |
67 | case Poppler::FormFieldChoice::ListBox: |
68 | out << "ListBox" ; |
69 | break; |
70 | } |
71 | return out; |
72 | } |
73 | |
74 | static std::ostream &operator<<(std::ostream &out, Poppler::SignatureValidationInfo::SignatureStatus status) |
75 | { |
76 | switch (status) { |
77 | case Poppler::SignatureValidationInfo::SignatureValid: |
78 | out << "Valid" ; |
79 | break; |
80 | case Poppler::SignatureValidationInfo::SignatureInvalid: |
81 | out << "Invalid" ; |
82 | break; |
83 | case Poppler::SignatureValidationInfo::SignatureDigestMismatch: |
84 | out << "DigestMismatch" ; |
85 | break; |
86 | case Poppler::SignatureValidationInfo::SignatureDecodingError: |
87 | out << "DecodingError" ; |
88 | break; |
89 | case Poppler::SignatureValidationInfo::SignatureGenericError: |
90 | out << "GenericError" ; |
91 | break; |
92 | case Poppler::SignatureValidationInfo::SignatureNotFound: |
93 | out << "NotFound" ; |
94 | break; |
95 | case Poppler::SignatureValidationInfo::SignatureNotVerified: |
96 | out << "NotVerifiedYet" ; |
97 | break; |
98 | } |
99 | return out; |
100 | } |
101 | |
102 | static std::ostream &operator<<(std::ostream &out, Poppler::SignatureValidationInfo::CertificateStatus status) |
103 | { |
104 | switch (status) { |
105 | case Poppler::SignatureValidationInfo::CertificateTrusted: |
106 | out << "Trusted" ; |
107 | break; |
108 | case Poppler::SignatureValidationInfo::CertificateUntrustedIssuer: |
109 | out << "UntrustedIssuer" ; |
110 | break; |
111 | case Poppler::SignatureValidationInfo::CertificateUnknownIssuer: |
112 | out << "UnknownIssuer" ; |
113 | break; |
114 | case Poppler::SignatureValidationInfo::CertificateRevoked: |
115 | out << "Revoked" ; |
116 | break; |
117 | case Poppler::SignatureValidationInfo::CertificateExpired: |
118 | out << "Expired" ; |
119 | break; |
120 | case Poppler::SignatureValidationInfo::CertificateGenericError: |
121 | out << "GenericError" ; |
122 | break; |
123 | case Poppler::SignatureValidationInfo::CertificateNotVerified: |
124 | out << "NotVerifiedYet" ; |
125 | break; |
126 | case Poppler::SignatureValidationInfo::CertificateVerificationInProgress: |
127 | out << "InProgress" ; |
128 | } |
129 | return out; |
130 | } |
131 | |
132 | static std::ostream &operator<<(std::ostream &out, Qt::Alignment alignment) |
133 | { |
134 | switch (alignment) { |
135 | case Qt::AlignLeft: |
136 | out << "Left" ; |
137 | break; |
138 | case Qt::AlignRight: |
139 | out << "Right" ; |
140 | break; |
141 | case Qt::AlignHCenter: |
142 | out << "HCenter" ; |
143 | break; |
144 | case Qt::AlignJustify: |
145 | out << "Justify" ; |
146 | break; |
147 | case Qt::AlignTop: |
148 | out << "Top" ; |
149 | break; |
150 | case Qt::AlignBottom: |
151 | out << "Bottom" ; |
152 | break; |
153 | case Qt::AlignVCenter: |
154 | out << "VCenter" ; |
155 | break; |
156 | case Qt::AlignCenter: |
157 | out << "Center" ; |
158 | break; |
159 | case Qt::AlignAbsolute: |
160 | out << "Absolute" ; |
161 | break; |
162 | } |
163 | return out; |
164 | } |
165 | |
166 | static std::ostream &operator<<(std::ostream &out, const QString &string) |
167 | { |
168 | out << string.toUtf8().constData(); |
169 | return out; |
170 | } |
171 | |
172 | static std::ostream &operator<<(std::ostream &out, const QRectF &rect) |
173 | { |
174 | out << QStringLiteral("top: %1 left: %2 width: %3 height: %4" ).arg(a: rect.x()).arg(a: rect.y()).arg(a: rect.width()).arg(a: rect.height()); |
175 | return out; |
176 | } |
177 | |
178 | template<typename T> |
179 | std::ostream &operator<<(std::ostream &out, const QList<T> &elems) |
180 | { |
181 | bool isFirst = true; |
182 | for (int i = 0; i < elems.count(); ++i) { |
183 | if (!isFirst) { |
184 | out << " " ; |
185 | } |
186 | out << elems[i]; |
187 | isFirst = false; |
188 | } |
189 | return out; |
190 | } |
191 | |
192 | int main(int argc, char **argv) |
193 | { |
194 | QCoreApplication a(argc, argv); |
195 | |
196 | if (!(argc == 2)) { |
197 | qWarning() << "usage: poppler-forms filename" ; |
198 | exit(status: 1); |
199 | } |
200 | |
201 | std::unique_ptr<Poppler::Document> doc = Poppler::Document::load(filePath: argv[1]); |
202 | if (!doc) { |
203 | qWarning() << "doc not loaded" ; |
204 | exit(status: 1); |
205 | } |
206 | |
207 | std::cout << "Forms for file " << argv[1] << std::endl; |
208 | for (int i = 0; i < doc->numPages(); ++i) { |
209 | std::unique_ptr<Poppler::Page> page = doc->page(index: i); |
210 | if (page) { |
211 | std::vector<std::unique_ptr<Poppler::FormField>> forms = page->formFields(); |
212 | std::cout << "\tPage " << i + 1 << std::endl; |
213 | for (const std::unique_ptr<Poppler::FormField> &form : forms) { |
214 | std::cout << "\t\tForm" << std::endl; |
215 | std::cout << "\t\t\tType: " << form->type() << std::endl; |
216 | std::cout << "\t\t\tRect: " << form->rect() << std::endl; |
217 | std::cout << "\t\t\tID: " << form->id() << std::endl; |
218 | std::cout << "\t\t\tName: " << form->name() << std::endl; |
219 | std::cout << "\t\t\tFullyQualifiedName: " << form->fullyQualifiedName() << std::endl; |
220 | std::cout << "\t\t\tUIName: " << form->uiName() << std::endl; |
221 | std::cout << "\t\t\tReadOnly: " << form->isReadOnly() << std::endl; |
222 | std::cout << "\t\t\tVisible: " << form->isVisible() << std::endl; |
223 | switch (form->type()) { |
224 | case Poppler::FormField::FormButton: { |
225 | const Poppler::FormFieldButton *buttonForm = static_cast<const Poppler::FormFieldButton *>(form.get()); |
226 | std::cout << "\t\t\tButtonType: " << buttonForm->buttonType() << std::endl; |
227 | std::cout << "\t\t\tCaption: " << buttonForm->caption() << std::endl; |
228 | std::cout << "\t\t\tState: " << buttonForm->state() << std::endl; |
229 | std::cout << "\t\t\tSiblings: " << buttonForm->siblings() << std::endl; |
230 | } break; |
231 | |
232 | case Poppler::FormField::FormText: { |
233 | const Poppler::FormFieldText *textForm = static_cast<const Poppler::FormFieldText *>(form.get()); |
234 | std::cout << "\t\t\tTextType: " << textForm->textType() << std::endl; |
235 | std::cout << "\t\t\tText: " << textForm->text() << std::endl; |
236 | std::cout << "\t\t\tIsPassword: " << textForm->isPassword() << std::endl; |
237 | std::cout << "\t\t\tIsRichText: " << textForm->isRichText() << std::endl; |
238 | std::cout << "\t\t\tMaximumLength: " << textForm->maximumLength() << std::endl; |
239 | std::cout << "\t\t\tTextAlignment: " << textForm->textAlignment() << std::endl; |
240 | std::cout << "\t\t\tCanBeSpellChecked: " << textForm->canBeSpellChecked() << std::endl; |
241 | } break; |
242 | |
243 | case Poppler::FormField::FormChoice: { |
244 | const Poppler::FormFieldChoice *choiceForm = static_cast<const Poppler::FormFieldChoice *>(form.get()); |
245 | std::cout << "\t\t\tChoiceType: " << choiceForm->choiceType() << std::endl; |
246 | std::cout << "\t\t\tChoices: " << choiceForm->choices() << std::endl; |
247 | std::cout << "\t\t\tIsEditable: " << choiceForm->isEditable() << std::endl; |
248 | std::cout << "\t\t\tIsMultiSelect: " << choiceForm->multiSelect() << std::endl; |
249 | std::cout << "\t\t\tCurrentChoices: " << choiceForm->currentChoices() << std::endl; |
250 | std::cout << "\t\t\tEditChoice: " << choiceForm->editChoice() << std::endl; |
251 | std::cout << "\t\t\tTextAlignment: " << choiceForm->textAlignment() << std::endl; |
252 | std::cout << "\t\t\tCanBeSpellChecked: " << choiceForm->canBeSpellChecked() << std::endl; |
253 | } break; |
254 | |
255 | case Poppler::FormField::FormSignature: { |
256 | const Poppler::FormFieldSignature *signatureForm = static_cast<const Poppler::FormFieldSignature *>(form.get()); |
257 | const Poppler::SignatureValidationInfo svi = signatureForm->validate(opt: Poppler::FormFieldSignature::ValidateVerifyCertificate); |
258 | std::cout << "\t\t\tSignatureStatus: " << svi.signatureStatus() << std::endl; |
259 | std::cout << "\t\t\tCertificateStatus: " << svi.certificateStatus() << std::endl; |
260 | if (svi.signerName().isEmpty() == false) { |
261 | std::cout << "\t\t\tSignerName: " << svi.signerName() << std::endl; |
262 | } else { |
263 | std::cout << "\t\t\tSignerName: " |
264 | << "(null)" << std::endl; |
265 | } |
266 | const QDateTime sviTime = QDateTime::fromSecsSinceEpoch(secs: svi.signingTime(), spec: Qt::UTC); |
267 | std::cout << "\t\t\tSigningTime: " << sviTime.toString() << std::endl; |
268 | } break; |
269 | } |
270 | } |
271 | } |
272 | } |
273 | } |
274 | |