001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.io.InputStream;
007import java.util.Arrays;
008
009import javax.xml.stream.XMLStreamConstants;
010import javax.xml.stream.XMLStreamException;
011
012import org.openstreetmap.josm.data.osm.DataSet;
013import org.openstreetmap.josm.data.osm.OsmPrimitive;
014import org.openstreetmap.josm.gui.progress.ProgressMonitor;
015
016/**
017 * Reader for <a href="http://wiki.openstreetmap.org/wiki/OsmChange">OsmChange</a> file format.
018 */
019public class OsmChangeReader extends OsmReader {
020
021    /**
022     * List of possible actions.
023     */
024    private static final String[] ACTIONS = {"create", "modify", "delete"};
025
026    /**
027     * constructor (for private and subclasses use only)
028     *
029     * @see #parseDataSet(InputStream, ProgressMonitor)
030     */
031    protected OsmChangeReader() {
032        // Restricts visibility
033    }
034
035    @Override
036    protected void parseRoot() throws XMLStreamException {
037        if ("osmChange".equals(parser.getLocalName())) {
038            parseOsmChange();
039        } else {
040            parseUnknown();
041        }
042    }
043
044    private void parseOsmChange() throws XMLStreamException {
045        String v = parser.getAttributeValue(null, "version");
046        if (v == null) {
047            throwException(tr("Missing mandatory attribute ''{0}''.", "version"));
048        }
049        if (!"0.6".equals(v)) {
050            throwException(tr("Unsupported version: {0}", v));
051        }
052        ds.setVersion(v);
053        while (parser.hasNext()) {
054            int event = parser.next();
055            if (event == XMLStreamConstants.START_ELEMENT) {
056                if (Arrays.asList(ACTIONS).contains(parser.getLocalName())) {
057                    parseCommon(parser.getLocalName());
058                } else {
059                    parseUnknown();
060                }
061            } else if (event == XMLStreamConstants.END_ELEMENT) {
062                return;
063            }
064        }
065    }
066
067    private void parseCommon(String action) throws XMLStreamException {
068        while (parser.hasNext()) {
069            int event = parser.next();
070            if (event == XMLStreamConstants.START_ELEMENT) {
071                OsmPrimitive p = null;
072                switch (parser.getLocalName()) {
073                case "node":
074                    p = parseNode();
075                    break;
076                case "way":
077                    p = parseWay();
078                    break;
079                case "relation":
080                    p = parseRelation();
081                    break;
082                default:
083                    parseUnknown();
084                }
085                if (p != null && action != null) {
086                    if ("modify".equals(action)) {
087                        p.setModified(true);
088                    } else if ("delete".equals(action)) {
089                        p.setDeleted(true);
090                    }
091                }
092            } else if (event == XMLStreamConstants.END_ELEMENT) {
093                return;
094            }
095        }
096    }
097
098    /**
099     * Parse the given input source and return the dataset.
100     *
101     * @param source the source input stream. Must not be <code>null</code>.
102     * @param progressMonitor  the progress monitor. If <code>null</code>,
103     * {@link org.openstreetmap.josm.gui.progress.NullProgressMonitor#INSTANCE} is assumed
104     *
105     * @return the dataset with the parsed data
106     * @throws IllegalDataException if the an error was found while parsing the data from the source
107     * @throws IllegalArgumentException if source is <code>null</code>
108     */
109    public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
110        return new OsmChangeReader().doParseDataSet(source, progressMonitor);
111    }
112}