source: josm/trunk/src/org/openstreetmap/josm/data/preferences/PreferencesReader.java@ 9798

Last change on this file since 9798 was 9798, checked in by stoecker, 8 years ago

fix Coverity issues 1351364 and 1351265

  • Property svn:eol-style set to native
File size: 9.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.preferences;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.BufferedReader;
7import java.io.File;
8import java.io.IOException;
9import java.io.InputStream;
10import java.io.Reader;
11import java.nio.charset.StandardCharsets;
12import java.nio.file.Files;
13import java.util.ArrayList;
14import java.util.Collections;
15import java.util.LinkedHashMap;
16import java.util.List;
17import java.util.Map;
18import java.util.SortedMap;
19import java.util.TreeMap;
20
21import javax.xml.XMLConstants;
22import javax.xml.stream.XMLInputFactory;
23import javax.xml.stream.XMLStreamConstants;
24import javax.xml.stream.XMLStreamException;
25import javax.xml.stream.XMLStreamReader;
26import javax.xml.transform.stream.StreamSource;
27import javax.xml.validation.Schema;
28import javax.xml.validation.SchemaFactory;
29import javax.xml.validation.Validator;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.io.CachedFile;
33import org.xml.sax.SAXException;
34
35/**
36 * Loads preferences from XML.
37 */
38public class PreferencesReader {
39
40 private final SortedMap<String, Setting<?>> settings = new TreeMap<>();
41 private int version = 0;
42 private XMLStreamReader parser;
43
44 /**
45 * Validate the XML.
46 * @param f the file
47 * @throws IOException if any I/O error occurs
48 * @throws SAXException if any SAX error occurs
49 */
50 public static void validateXML(File f) throws IOException, SAXException {
51 try (BufferedReader in = Files.newBufferedReader(f.toPath(), StandardCharsets.UTF_8)) {
52 validateXML(in);
53 }
54 }
55
56 /**
57 * Validate the XML.
58 * @param in the {@link Reader}
59 * @throws IOException if any I/O error occurs
60 * @throws SAXException if any SAX error occurs
61 */
62 public static void validateXML(Reader in) throws IOException, SAXException {
63 try (CachedFile cf = new CachedFile("resource://data/preferences.xsd"); InputStream xsdStream = cf.getInputStream()) {
64 Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(new StreamSource(xsdStream));
65 Validator validator = schema.newValidator();
66 validator.validate(new StreamSource(in));
67 }
68 }
69
70 /**
71 * Parse preferences XML.
72 * @param f the file
73 * @throws IOException if any I/O error occurs
74 * @throws XMLStreamException if any XML stream error occurs
75 */
76 public void fromXML(File f) throws IOException, XMLStreamException {
77 try (BufferedReader in = Files.newBufferedReader(f.toPath(), StandardCharsets.UTF_8)) {
78 fromXML(in);
79 }
80 }
81
82 /**
83 * Parse preferences XML.
84 * @param in the {@link Reader}
85 * @throws XMLStreamException if any XML stream error occurs
86 */
87 public void fromXML(Reader in) throws XMLStreamException {
88 this.parser = XMLInputFactory.newInstance().createXMLStreamReader(in);
89 parse();
90 }
91
92 /**
93 * Return the parsed preferences as a settings map
94 * @return the parsed preferences as a settings map
95 */
96 public SortedMap<String, Setting<?>> getSettings() {
97 return settings;
98 }
99
100 /**
101 * Return the version from the XML root element.
102 * (Represents the JOSM version when the file was written.)
103 * @return the version
104 */
105 public int getVersion() {
106 return version;
107 }
108
109 private void parse() throws XMLStreamException {
110 int event = parser.getEventType();
111 while (true) {
112 if (event == XMLStreamConstants.START_ELEMENT) {
113 try {
114 version = Integer.parseInt(parser.getAttributeValue(null, "version"));
115 } catch (NumberFormatException e) {
116 if (Main.isDebugEnabled()) {
117 Main.debug(e.getMessage());
118 }
119 }
120 parseRoot();
121 } else if (event == XMLStreamConstants.END_ELEMENT) {
122 return;
123 }
124 if (parser.hasNext()) {
125 event = parser.next();
126 } else {
127 break;
128 }
129 }
130 parser.close();
131 }
132
133 private void parseRoot() throws XMLStreamException {
134 while (true) {
135 int event = parser.next();
136 if (event == XMLStreamConstants.START_ELEMENT) {
137 String localName = parser.getLocalName();
138 switch(localName) {
139 case "tag":
140 settings.put(parser.getAttributeValue(null, "key"), new StringSetting(parser.getAttributeValue(null, "value")));
141 jumpToEnd();
142 break;
143 case "list":
144 case "collection":
145 case "lists":
146 case "maps":
147 parseToplevelList();
148 break;
149 default:
150 throwException("Unexpected element: "+localName);
151 }
152 } else if (event == XMLStreamConstants.END_ELEMENT) {
153 return;
154 }
155 }
156 }
157
158 private void jumpToEnd() throws XMLStreamException {
159 while (true) {
160 int event = parser.next();
161 if (event == XMLStreamConstants.START_ELEMENT) {
162 jumpToEnd();
163 } else if (event == XMLStreamConstants.END_ELEMENT) {
164 return;
165 }
166 }
167 }
168
169 private void parseToplevelList() throws XMLStreamException {
170 String key = parser.getAttributeValue(null, "key");
171 String name = parser.getLocalName();
172
173 List<String> entries = null;
174 List<List<String>> lists = null;
175 List<Map<String, String>> maps = null;
176 while (true) {
177 int event = parser.next();
178 if (event == XMLStreamConstants.START_ELEMENT) {
179 String localName = parser.getLocalName();
180 switch(localName) {
181 case "entry":
182 if (entries == null) {
183 entries = new ArrayList<>();
184 }
185 entries.add(parser.getAttributeValue(null, "value"));
186 jumpToEnd();
187 break;
188 case "list":
189 if (lists == null) {
190 lists = new ArrayList<>();
191 }
192 lists.add(parseInnerList());
193 break;
194 case "map":
195 if (maps == null) {
196 maps = new ArrayList<>();
197 }
198 maps.add(parseMap());
199 break;
200 default:
201 throwException("Unexpected element: "+localName);
202 }
203 } else if (event == XMLStreamConstants.END_ELEMENT) {
204 break;
205 }
206 }
207 if (entries != null) {
208 settings.put(key, new ListSetting(Collections.unmodifiableList(entries)));
209 } else if (lists != null) {
210 settings.put(key, new ListListSetting(Collections.unmodifiableList(lists)));
211 } else if (maps != null) {
212 settings.put(key, new MapListSetting(Collections.unmodifiableList(maps)));
213 } else {
214 if ("lists".equals(name)) {
215 settings.put(key, new ListListSetting(Collections.<List<String>>emptyList()));
216 } else if ("maps".equals(name)) {
217 settings.put(key, new MapListSetting(Collections.<Map<String, String>>emptyList()));
218 } else {
219 settings.put(key, new ListSetting(Collections.<String>emptyList()));
220 }
221 }
222 }
223
224 private List<String> parseInnerList() throws XMLStreamException {
225 List<String> entries = new ArrayList<>();
226 while (true) {
227 int event = parser.next();
228 if (event == XMLStreamConstants.START_ELEMENT) {
229 if ("entry".equals(parser.getLocalName())) {
230 entries.add(parser.getAttributeValue(null, "value"));
231 jumpToEnd();
232 } else {
233 throwException("Unexpected element: "+parser.getLocalName());
234 }
235 } else if (event == XMLStreamConstants.END_ELEMENT) {
236 break;
237 }
238 }
239 return Collections.unmodifiableList(entries);
240 }
241
242 private Map<String, String> parseMap() throws XMLStreamException {
243 Map<String, String> map = new LinkedHashMap<>();
244 while (true) {
245 int event = parser.next();
246 if (event == XMLStreamConstants.START_ELEMENT) {
247 if ("tag".equals(parser.getLocalName())) {
248 map.put(parser.getAttributeValue(null, "key"), parser.getAttributeValue(null, "value"));
249 jumpToEnd();
250 } else {
251 throwException("Unexpected element: "+parser.getLocalName());
252 }
253 } else if (event == XMLStreamConstants.END_ELEMENT) {
254 break;
255 }
256 }
257 return Collections.unmodifiableMap(map);
258 }
259
260 private void throwException(String msg) {
261 throw new RuntimeException(msg + tr(" (at line {0}, column {1})",
262 parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber()));
263 }
264}
Note: See TracBrowser for help on using the repository browser.