source: josm/trunk/src/org/openstreetmap/josm/io/OsmChangeReader.java@ 14397

Last change on this file since 14397 was 14314, checked in by Don-vip, 6 years ago

fix #16834 - IAE when opening .osmc containing empty note created by OsmAnd

  • Property svn:eol-style set to native
File size: 6.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.InputStream;
7import java.util.Arrays;
8
9import javax.xml.stream.XMLStreamConstants;
10import javax.xml.stream.XMLStreamException;
11
12import org.openstreetmap.josm.data.coor.LatLon;
13import org.openstreetmap.josm.data.osm.DataSet;
14import org.openstreetmap.josm.data.osm.NoteData;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.gui.progress.ProgressMonitor;
17import org.openstreetmap.josm.tools.Pair;
18
19/**
20 * Reader for <a href="http://wiki.openstreetmap.org/wiki/OsmChange">OsmChange</a> file format.
21 */
22public class OsmChangeReader extends OsmReader {
23
24 /**
25 * List of possible actions.
26 */
27 private static final String[] ACTIONS = {"create", "modify", "delete"};
28
29 protected final NoteData noteData = new NoteData();
30
31 /**
32 * constructor (for private and subclasses use only)
33 *
34 * @see #parseDataSet(InputStream, ProgressMonitor)
35 */
36 protected OsmChangeReader() {
37 // Restricts visibility
38 }
39
40 @Override
41 protected void parseRoot() throws XMLStreamException {
42 if ("osmChange".equals(parser.getLocalName())) {
43 parseOsmChange();
44 } else {
45 parseUnknown();
46 }
47 }
48
49 private void parseOsmChange() throws XMLStreamException {
50 String v = parser.getAttributeValue(null, "version");
51 if (v == null) {
52 throwException(tr("Missing mandatory attribute ''{0}''.", "version"));
53 }
54 if (!"0.6".equals(v)) {
55 throwException(tr("Unsupported version: {0}", v));
56 }
57 ds.setVersion(v);
58 while (parser.hasNext()) {
59 int event = parser.next();
60 if (event == XMLStreamConstants.START_ELEMENT) {
61 if (Arrays.asList(ACTIONS).contains(parser.getLocalName())) {
62 parseCommon(parser.getLocalName());
63 } else {
64 parseUnknown();
65 }
66 } else if (event == XMLStreamConstants.END_ELEMENT) {
67 return;
68 }
69 }
70 }
71
72 private void parseCommon(String action) throws XMLStreamException {
73 while (parser.hasNext()) {
74 int event = parser.next();
75 if (event == XMLStreamConstants.START_ELEMENT) {
76 OsmPrimitive p = null;
77 switch (parser.getLocalName()) {
78 case "node":
79 p = parseNode();
80 break;
81 case "way":
82 p = parseWay();
83 break;
84 case "relation":
85 p = parseRelation();
86 break;
87 case "note":
88 parseNote();
89 break;
90 default:
91 parseUnknown();
92 }
93 if (p != null && action != null) {
94 if ("modify".equals(action)) {
95 p.setModified(true);
96 } else if ("delete".equals(action)) {
97 p.setDeleted(true);
98 }
99 }
100 } else if (event == XMLStreamConstants.END_ELEMENT) {
101 return;
102 }
103 }
104 }
105
106 private void parseNote() throws XMLStreamException {
107 LatLon location = NoteReader.parseLatLon(s -> parser.getAttributeValue(null, s));
108 String text = null;
109 while (parser.hasNext()) {
110 int event = parser.next();
111 if (event == XMLStreamConstants.START_ELEMENT) {
112 switch (parser.getLocalName()) {
113 case "comment":
114 text = parser.getAttributeValue(null, "text");
115 jumpToEnd();
116 break;
117 default:
118 parseUnknown();
119 }
120 } else if (event == XMLStreamConstants.END_ELEMENT) {
121 break;
122 }
123 }
124 if (location != null && text != null && !text.isEmpty()) {
125 noteData.createNote(location, text);
126 }
127 }
128
129 /**
130 * Replies the parsed notes data.
131 * @return the parsed notes data
132 * @since 14101
133 */
134 public final NoteData getNoteData() {
135 return noteData;
136 }
137
138 /**
139 * Parse the given input source and return the dataset.
140 *
141 * @param source the source input stream. Must not be <code>null</code>.
142 * @param progressMonitor the progress monitor. If <code>null</code>,
143 * {@link org.openstreetmap.josm.gui.progress.NullProgressMonitor#INSTANCE} is assumed
144 *
145 * @return the dataset with the parsed data
146 * @throws IllegalDataException if the an error was found while parsing the data from the source
147 * @throws IllegalArgumentException if source is <code>null</code>
148 */
149 public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
150 return new OsmChangeReader().doParseDataSet(source, progressMonitor);
151 }
152
153 /**
154 * Parse the given input source and return the dataset and notes, if any (OsmAnd extends the osmChange format by adding notes).
155 *
156 * @param source the source input stream. Must not be <code>null</code>.
157 * @param progressMonitor the progress monitor. If <code>null</code>,
158 * {@link org.openstreetmap.josm.gui.progress.NullProgressMonitor#INSTANCE} is assumed
159 *
160 * @return the dataset with the parsed data
161 * @throws IllegalDataException if the an error was found while parsing the data from the source
162 * @throws IllegalArgumentException if source is <code>null</code>
163 * @since 14101
164 */
165 public static Pair<DataSet, NoteData> parseDataSetAndNotes(InputStream source, ProgressMonitor progressMonitor)
166 throws IllegalDataException {
167 OsmChangeReader osmChangeReader = new OsmChangeReader();
168 osmChangeReader.doParseDataSet(source, progressMonitor);
169 return new Pair<>(osmChangeReader.getDataSet(), osmChangeReader.getNoteData());
170 }
171}
Note: See TracBrowser for help on using the repository browser.