1 | /* | |
2 | * | |
3 | * Copyright 2004 by Leonard Rosenthol. | |
4 | * | |
5 | * The contents of this file are subject to the Mozilla Public License Version 1.1 | |
6 | * (the "License"); you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at http://www.mozilla.org/MPL/ | |
8 | * | |
9 | * Software distributed under the License is distributed on an "AS IS" basis, | |
10 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
11 | * for the specific language governing rights and limitations under the License. | |
12 | * | |
13 | * The Original Code is 'iText, a free JAVA-PDF library'. | |
14 | * | |
15 | * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by | |
16 | * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. | |
17 | * All Rights Reserved. | |
18 | * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer | |
19 | * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. | |
20 | * | |
21 | * Contributor(s): all the names of the contributors are added in the source code | |
22 | * where applicable. | |
23 | * | |
24 | * Alternatively, the contents of this file may be used under the terms of the | |
25 | * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the | |
26 | * provisions of LGPL are applicable instead of those above. If you wish to | |
27 | * allow use of your version of this file only under the terms of the LGPL | |
28 | * License and not to allow others to use your version of this file under | |
29 | * the MPL, indicate your decision by deleting the provisions above and | |
30 | * replace them with the notice and other provisions required by the LGPL. | |
31 | * If you do not delete the provisions above, a recipient may use your version | |
32 | * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. | |
33 | * | |
34 | * This library is free software; you can redistribute it and/or modify it | |
35 | * under the terms of the MPL as stated above or under the terms of the GNU | |
36 | * Library General Public License as published by the Free Software Foundation; | |
37 | * either version 2 of the License, or any later version. | |
38 | * | |
39 | * This library is distributed in the hope that it will be useful, but WITHOUT | |
40 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
41 | * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more | |
42 | * details. | |
43 | * | |
44 | * If you didn't download this code from the following link, you should check if | |
45 | * you aren't using an obsolete version: | |
46 | * http://www.lowagie.com/iText/ | |
47 | */ | |
48 | ||
49 | package com.lowagie.text.pdf; | |
50 | ||
51 | import com.lowagie.text.error_messages.MessageLocalization; | |
52 | import com.lowagie.text.xml.simpleparser.SimpleXMLDocHandler; | |
53 | import com.lowagie.text.xml.simpleparser.SimpleXMLParser; | |
54 | ||
55 | import java.io.ByteArrayInputStream; | |
56 | import java.io.FileInputStream; | |
57 | import java.io.IOException; | |
58 | import java.util.*; | |
59 | ||
60 | /** | |
61 | * Reads a XFDF. | |
62 | * | |
63 | * @author Leonard Rosenthol (leonardr@pdfsages.com) | |
64 | */ | |
65 | public class XfdfReader implements SimpleXMLDocHandler, FieldReader { | |
66 | ||
67 | // stuff used during parsing to handle state | |
68 | private boolean foundRoot = false; | |
69 | private Stack<String> fieldNames = new Stack<>(); | |
70 | private Stack<String> fieldValues = new Stack<>(); | |
71 | ||
72 | // storage for the field list and their values | |
73 | private Map<String, String> fields; | |
74 | /** | |
75 | * Storage for field values if there's more than one value for a field. | |
76 | * | |
77 | * @since 2.1.4 | |
78 | */ | |
79 | private Map<String, List<String>> listFields; | |
80 | ||
81 | // storage for the path to referenced PDF, if any | |
82 | private String fileSpec; | |
83 | ||
84 | /** | |
85 | * Reads an XFDF form. | |
86 | * | |
87 | * @param filename the file name of the form | |
88 | * @throws IOException on error | |
89 | */ | |
90 | public XfdfReader(String filename) throws IOException { | |
91 | try (FileInputStream fin = new FileInputStream(filename)) { | |
92 |
1
1. |
SimpleXMLParser.parse(this, fin); |
93 | } | |
94 | } | |
95 | ||
96 | /** | |
97 | * Reads an XFDF form. | |
98 | * | |
99 | * @param xfdfIn the byte array with the form | |
100 | * @throws IOException on error | |
101 | */ | |
102 | public XfdfReader(byte[] xfdfIn) throws IOException { | |
103 |
1
1. |
SimpleXMLParser.parse(this, new ByteArrayInputStream(xfdfIn)); |
104 | } | |
105 | ||
106 | /** | |
107 | * Gets all the fields. The map is keyed by the fully qualified field name and the value is a merged | |
108 | * <CODE>PdfDictionary</CODE> with the | |
109 | * field content. | |
110 | * | |
111 | * @return all the fields | |
112 | */ | |
113 | public Map<String, String> getFields() { | |
114 | return fields; | |
115 | } | |
116 | ||
117 | /** | |
118 | * Gets the field value. | |
119 | * | |
120 | * @param name the fully qualified field name | |
121 | * @return the field's value | |
122 | */ | |
123 | public String getField(String name) { | |
124 |
1
1. getField : mutated return of Object value for com/lowagie/text/pdf/XfdfReader::getField to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return fields.get(name); |
125 | } | |
126 | ||
127 | /** | |
128 | * Gets the field value or <CODE>null</CODE> if the field does not exist or has no value defined. | |
129 | * | |
130 | * @param name the fully qualified field name | |
131 | * @return the field value or <CODE>null</CODE> | |
132 | */ | |
133 | public String getFieldValue(String name) { | |
134 |
1
1. getFieldValue : mutated return of Object value for com/lowagie/text/pdf/XfdfReader::getFieldValue to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return fields.get(name); |
135 | } | |
136 | ||
137 | /** | |
138 | * Gets the field values for a list or <CODE>null</CODE> if the field does not exist or has no value defined. | |
139 | * | |
140 | * @param name the fully qualified field name | |
141 | * @return the field values or <CODE>null</CODE> | |
142 | * @since 2.1.4 | |
143 | */ | |
144 | public List<String> getListValues(String name) { | |
145 |
1
1. getListValues : mutated return of Object value for com/lowagie/text/pdf/XfdfReader::getListValues to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return listFields.get(name); |
146 | } | |
147 | ||
148 | /** | |
149 | * Gets the PDF file specification contained in the FDF. | |
150 | * | |
151 | * @return the PDF file specification contained in the FDF | |
152 | */ | |
153 | public String getFileSpec() { | |
154 | return fileSpec; | |
155 | } | |
156 | ||
157 | /** | |
158 | * Called when a start tag is found. | |
159 | * | |
160 | * @param tag the tag name | |
161 | * @param h the tag's attributes | |
162 | */ | |
163 | public void startElement(String tag, Map<String, String> h) { | |
164 |
1
1. startElement : negated conditional → NO_COVERAGE |
if (!foundRoot) { |
165 |
1
1. startElement : negated conditional → NO_COVERAGE |
if (!tag.equals("xfdf")) { |
166 | throw new RuntimeException(MessageLocalization.getComposedMessage("root.element.is.not.xfdf.1", tag)); | |
167 | } else { | |
168 | foundRoot = true; | |
169 | } | |
170 | } | |
171 | ||
172 | switch (tag) { | |
173 | case "xfdf": | |
174 | // intentionally left blank | |
175 | break; | |
176 | case "f": | |
177 | fileSpec = h.get("href"); | |
178 | break; | |
179 | case "fields": | |
180 | fields = new HashMap<>(); // init it! | |
181 | ||
182 | listFields = new HashMap<>(); | |
183 | break; | |
184 | case "field": | |
185 | String fName = h.get("name"); | |
186 | fieldNames.push(fName); | |
187 | break; | |
188 | case "value": | |
189 | fieldValues.push(""); | |
190 | break; | |
191 | } | |
192 | } | |
193 | ||
194 | /** | |
195 | * Called when an end tag is found. | |
196 | * | |
197 | * @param tag the tag name | |
198 | */ | |
199 | public void endElement(String tag) { | |
200 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (tag.equals("value")) { |
201 | StringBuilder fName = new StringBuilder(); | |
202 |
2
1. endElement : changed conditional boundary → NO_COVERAGE 2. endElement : negated conditional → NO_COVERAGE |
for (int k = 0; k < fieldNames.size(); ++k) { |
203 | fName.append(".").append(fieldNames.elementAt(k)); | |
204 | } | |
205 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (fName.toString().startsWith(".")) { |
206 | fName = new StringBuilder(fName.substring(1)); | |
207 | } | |
208 | String fVal = fieldValues.pop(); | |
209 | String old = fields.put(fName.toString(), fVal); | |
210 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (old != null) { |
211 | List<String> l = listFields.get(fName.toString()); | |
212 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (l == null) { |
213 | l = new ArrayList<>(); | |
214 | l.add(old); | |
215 | } | |
216 | l.add(fVal); | |
217 | listFields.put(fName.toString(), l); | |
218 | } | |
219 |
1
1. endElement : negated conditional → NO_COVERAGE |
} else if (tag.equals("field")) { |
220 |
1
1. endElement : negated conditional → NO_COVERAGE |
if (!fieldNames.isEmpty()) { |
221 | fieldNames.pop(); | |
222 | } | |
223 | } | |
224 | } | |
225 | ||
226 | /** | |
227 | * Called when the document starts to be parsed. | |
228 | */ | |
229 | public void startDocument() { | |
230 | fileSpec = ""; | |
231 | } | |
232 | ||
233 | /** | |
234 | * Called after the document is parsed. | |
235 | */ | |
236 | public void endDocument() { | |
237 | ||
238 | } | |
239 | ||
240 | /** | |
241 | * Called when a text element is found. | |
242 | * | |
243 | * @param str the text element, probably a fragment. | |
244 | */ | |
245 | public void text(String str) { | |
246 |
2
1. text : negated conditional → NO_COVERAGE 2. text : negated conditional → NO_COVERAGE |
if (fieldNames.isEmpty() || fieldValues.isEmpty()) { |
247 | return; | |
248 | } | |
249 | ||
250 | String val = fieldValues.pop(); | |
251 | val += str; | |
252 | fieldValues.push(val); | |
253 | } | |
254 | } | |
Mutations | ||
92 |
1.1 |
|
103 |
1.1 |
|
124 |
1.1 |
|
134 |
1.1 |
|
145 |
1.1 |
|
164 |
1.1 |
|
165 |
1.1 |
|
200 |
1.1 |
|
202 |
1.1 2.2 |
|
205 |
1.1 |
|
210 |
1.1 |
|
212 |
1.1 |
|
219 |
1.1 |
|
220 |
1.1 |
|
246 |
1.1 2.2 |