Index: build.xml
===================================================================
--- build.xml	(revision 34950)
+++ build.xml	(working copy)
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <project name="reverter" default="dist" basedir=".">
-    <!-- enter the SVN commit message -->
-    <property name="commit.message" value="Reverter: Update MultiOsmReader to support null data after redaction"/>
-    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
-    <property name="plugin.main.version" value="14153"/>
-
-    <!-- Configure these properties (replace "..." accordingly).
-         See https://josm.openstreetmap.de/wiki/DevelopersGuide/DevelopingPlugins
+    <!-- enter the SVN commit message -->
+    <property name="commit.message" value="Reverter: Update MultiOsmReader to support null data after redaction"/>
+    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
+    <property name="plugin.main.version" value="xxx"/>
+
+    <!-- Configure these properties (replace "..." accordingly).
+         See https://josm.openstreetmap.de/wiki/DevelopersGuide/DevelopingPlugins
     -->
     <property name="plugin.author" value="Upliner"/>
     <property name="plugin.class" value="reverter.ReverterPlugin"/>
Index: src/reverter/ChangesetReverter.java
===================================================================
--- src/reverter/ChangesetReverter.java	(revision 34950)
+++ src/reverter/ChangesetReverter.java	(working copy)
@@ -8,6 +8,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -18,6 +19,9 @@
 import org.openstreetmap.josm.data.conflict.Conflict;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetDataSet;
+import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetDataSetEntry;
+import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetModificationType;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -37,18 +41,14 @@
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
 import org.openstreetmap.josm.io.OsmApiException;
+import org.openstreetmap.josm.io.OsmServerChangesetReader;
 import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
-
-import reverter.corehacks.ChangesetDataSet;
-import reverter.corehacks.ChangesetDataSet.ChangesetDataSetEntry;
-import reverter.corehacks.ChangesetDataSet.ChangesetModificationType;
-import reverter.corehacks.OsmServerChangesetReader;
-
-/**
- * Fetches and stores data for reverting of specific changeset.
- * @author Upliner
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Fetches and stores data for reverting of specific changeset.
+ * @author Upliner
  *
  */
 public class ChangesetReverter {
@@ -78,6 +78,7 @@
     private final HashSet<HistoryOsmPrimitive> created = new HashSet<>();
     private final HashSet<HistoryOsmPrimitive> updated = new HashSet<>();
     private final HashSet<HistoryOsmPrimitive> deleted = new HashSet<>();
+    private final HashMap<PrimitiveId, Integer> earliestVersion = new HashMap<>();
 
     //// Handling missing objects
     ////////////////////////////////////////
@@ -137,15 +138,15 @@
         } else {
             this.layer = MainApplication.getLayerManager().getEditLayer();
             this.ds = layer.data;
-        }
-        this.revertType = revertType;
-
-        OsmServerChangesetReader csr = new OsmServerChangesetReader();
-        monitor.beginTask("", 2);
-        changeset = csr.readChangeset(changesetId, monitor.createSubTaskMonitor(1, false));
-        if (MODERATOR_REDACTION_ACCOUNTS.contains(changeset.getUser().getId())) {
-            throw new RevertRedactedChangesetException(tr("It is not allowed to revert changeset from {0}", changeset.getUser().getName()));
-        }
+        }
+        this.revertType = revertType;
+
+        OsmServerChangesetReader csr = new OsmServerChangesetReader(true);
+        monitor.beginTask("", 2);
+        changeset = csr.readChangeset(changesetId, false, monitor.createSubTaskMonitor(1, false));
+        if (MODERATOR_REDACTION_ACCOUNTS.contains(changeset.getUser().getId())) {
+            throw new RevertRedactedChangesetException(tr("It is not allowed to revert changeset from {0}", changeset.getUser().getName()));
+        }
         try {
             cds = csr.downloadChangeset(changesetId, monitor.createSubTaskMonitor(1, false));
         } finally {
@@ -156,16 +157,16 @@
         }
 
         // Build our own lists of created/updated/modified objects for better performance
-        for (Iterator<ChangesetDataSetEntry> it = cds.iterator(); it.hasNext();) {
-            ChangesetDataSetEntry entry = it.next();
-            if (!checkOsmChangeEntry(entry)) continue;
-            if (entry.getModificationType() == ChangesetModificationType.CREATED) {
-                created.add(entry.getPrimitive());
-            } else if (entry.getModificationType() == ChangesetModificationType.UPDATED) {
-                updated.add(entry.getPrimitive());
-            } else if (entry.getModificationType() == ChangesetModificationType.DELETED) {
-                deleted.add(entry.getPrimitive());
-            } else throw new AssertionError();
+        for (PrimitiveId id : cds.getIds()) {
+        	ChangesetDataSetEntry first = cds.getFirstEntry(id);
+        	ChangesetDataSetEntry last = cds.getLastEntry(id);
+        	earliestVersion.put(id, (int) first.getPrimitive().getVersion());
+        	if (first.getModificationType() == ChangesetModificationType.CREATED)
+        		created.add(first.getPrimitive());
+        	else if (last.getModificationType() == ChangesetModificationType.UPDATED)
+        		updated.add(last.getPrimitive());
+        	else if (last.getModificationType() == ChangesetModificationType.DELETED)
+        		deleted.add(last.getPrimitive());
         }
     }
 
@@ -215,13 +216,16 @@
 
         progressMonitor.beginTask(tr("Downloading objects history"), updated.size()+deleted.size()+1);
         try {
-            for (HashSet<HistoryOsmPrimitive> collection : Arrays.asList(updated, deleted)) {
-                for (HistoryOsmPrimitive entry : collection) {
+            for (HashSet<HistoryOsmPrimitive> collection : Arrays.asList(updated, deleted)) {
+                for (HistoryOsmPrimitive entry : collection) {
                     PrimitiveId id = entry.getPrimitiveId();
-                    readObjectVersion(rdr, id, cds.getEarliestVersion(id)-1, progressMonitor);
-                    if (progressMonitor.isCanceled()) return;
-                }
-            }
+                    Integer earliest = earliestVersion.get(id);
+                    if (earliest == null || earliest <= 1)
+                    	throw new OsmTransferException(tr("Unexpected data in changeset #{1}" , String.valueOf(changesetId)));
+					readObjectVersion(rdr, id, earliestVersion.get(id) - 1, progressMonitor);
+                    if (progressMonitor.isCanceled()) return;
+                }
+            }
             nds = rdr.parseOsm(progressMonitor.createSubTaskMonitor(1, true));
             for (OsmPrimitive p : nds.allPrimitives()) {
                 if (!p.isIncomplete()) {
Index: src/reverter/corehacks/ChangesetDataSet.java
===================================================================
--- src/reverter/corehacks/ChangesetDataSet.java	(revision 34950)
+++ src/reverter/corehacks/ChangesetDataSet.java	(nonexistent)
@@ -1,238 +0,0 @@
-// License: GPL. For details, see LICENSE file.
-package reverter.corehacks;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.openstreetmap.josm.data.osm.PrimitiveId;
-import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
-import org.openstreetmap.josm.tools.CheckParameterUtil;
-
-/**
- * A ChangesetDataSet holds the content of a changeset.
- */
-public class ChangesetDataSet {
-
-    public enum ChangesetModificationType {
-        CREATED,
-        UPDATED,
-        DELETED
-    }
-
-    public interface ChangesetDataSetEntry {
-        ChangesetModificationType getModificationType();
-
-        HistoryOsmPrimitive getPrimitive();
-
-        int getEarliestVersion();
-    }
-
-    private final Map<PrimitiveId, Integer> earliestVersions = new HashMap<>();
-    private final Map<PrimitiveId, HistoryOsmPrimitive> primitives = new HashMap<>();
-    private final Map<PrimitiveId, ChangesetModificationType> modificationTypes = new HashMap<>();
-
-    /**
-     * Remembers a history primitive with the given modification type
-     *
-     * @param primitive the primitive. Must not be null.
-     * @param cmt the modification type. Must not be null.
-     * @throws IllegalArgumentException thrown if primitive is null
-     * @throws IllegalArgumentException thrown if cmt is null
-     */
-    public void put(HistoryOsmPrimitive primitive, ChangesetModificationType cmt) throws IllegalArgumentException {
-        CheckParameterUtil.ensureParameterNotNull(primitive, "primitive");
-        CheckParameterUtil.ensureParameterNotNull(cmt, "cmt");
-        PrimitiveId pid = primitive.getPrimitiveId();
-        if (primitives.containsKey(pid)) {
-            // Save only latest versions of primitives for reverter
-            if (primitive.getVersion() < primitives.get(pid).getVersion()) {
-                Integer earliest = earliestVersions.get(pid);
-                if (earliest == null || primitive.getVersion() < earliest) {
-                    earliestVersions.put(pid, (int) primitive.getVersion());
-                    if (cmt == ChangesetModificationType.CREATED)
-                        modificationTypes.put(pid, cmt);
-                }
-                return;
-            } else {
-                if (modificationTypes.get(pid) == ChangesetModificationType.CREATED) {
-                    cmt = ChangesetModificationType.CREATED;
-                }
-                if (earliestVersions.get(pid) == null) {
-                    earliestVersions.put(pid, (int) primitives.get(pid).getVersion());
-                }
-            }
-        }
-        primitives.put(pid, primitive);
-        modificationTypes.put(pid, cmt);
-    }
-
-    /**
-     * Replies true if the changeset content contains the object with primitive <code>id</code>.
-     * @param id the id.
-     * @return true if the changeset content contains the object with primitive <code>id</code>
-     */
-    public boolean contains(PrimitiveId id) {
-        if (id == null) return false;
-        return primitives.containsKey(id);
-    }
-
-    /**
-     * Replies the modification type for the object with id <code>id</code>. Replies null, if id is null or
-     * if the object with id <code>id</code> isn't in the changeset content.
-     *
-     * @param id the id
-     * @return the modification type
-     */
-    public ChangesetModificationType getModificationType(PrimitiveId id) {
-        if (!contains(id)) return null;
-        return modificationTypes.get(id);
-    }
-
-    public int getEarliestVersion(PrimitiveId id) {
-        Integer earliestVersion = earliestVersions.get(id);
-        if (earliestVersion == null) earliestVersion = (int) primitives.get(id).getVersion();
-        return earliestVersion;
-    }
-
-    /**
-     * Replies true if the primitive with id <code>id</code> was created in this
-     * changeset. Replies false, if id is null.
-     *
-     * @param id the id
-     * @return true if the primitive with id <code>id</code> was created in this
-     * changeset.
-     */
-    public boolean isCreated(PrimitiveId id) {
-        if (!contains(id)) return false;
-        return ChangesetModificationType.CREATED.equals(getModificationType(id));
-    }
-
-    /**
-     * Replies true if the primitive with id <code>id</code> was updated in this
-     * changeset. Replies false, if id is null.
-     *
-     * @param id the id
-     * @return true if the primitive with id <code>id</code> was updated in this
-     * changeset.
-     */
-    public boolean isUpdated(PrimitiveId id) {
-        if (!contains(id)) return false;
-        return ChangesetModificationType.UPDATED.equals(getModificationType(id));
-    }
-
-    /**
-     * Replies true if the primitive with id <code>id</code> was deleted in this
-     * changeset. Replies false, if id is null.
-     *
-     * @param id the id
-     * @return true if the primitive with id <code>id</code> was deleted in this
-     * changeset.
-     */
-    public boolean isDeleted(PrimitiveId id) {
-        if (!contains(id)) return false;
-        return ChangesetModificationType.DELETED.equals(getModificationType(id));
-    }
-
-    /**
-     * Replies the set of primitives with a specific modification type
-     *
-     * @param cmt the modification type. Must not be null.
-     * @return the set of primitives
-     * @throws IllegalArgumentException thrown if cmt is null
-     */
-    public Set<HistoryOsmPrimitive> getPrimitivesByModificationType(ChangesetModificationType cmt) throws IllegalArgumentException {
-        CheckParameterUtil.ensureParameterNotNull(cmt, "cmt");
-        HashSet<HistoryOsmPrimitive> ret = new HashSet<>();
-        for (Entry<PrimitiveId, ChangesetModificationType> entry: modificationTypes.entrySet()) {
-            if (entry.getValue().equals(cmt)) {
-                ret.add(primitives.get(entry.getKey()));
-            }
-        }
-        return ret;
-    }
-
-    /**
-     * Replies the number of objects in the dataset
-     *
-     * @return the number of objects in the dataset
-     */
-    public int size() {
-        return primitives.size();
-    }
-
-    /**
-     * Replies the {@link HistoryOsmPrimitive} with id <code>id</code> from this
-     * dataset. null, if there is no such primitive in the data set.
-     *
-     * @param id the id
-     * @return  the {@link HistoryOsmPrimitive} with id <code>id</code> from this
-     * dataset
-     */
-    public HistoryOsmPrimitive getPrimitive(PrimitiveId id) {
-        if (id == null) return null;
-        return primitives.get(id);
-    }
-
-    public Iterator<ChangesetDataSetEntry> iterator() {
-        return new DefaultIterator();
-    }
-
-    private static class DefaultChangesetDataSetEntry implements ChangesetDataSetEntry {
-        private final ChangesetModificationType modificationType;
-        private final HistoryOsmPrimitive primitive;
-        private final int earliestVersion;
-
-        DefaultChangesetDataSetEntry(ChangesetModificationType modificationType, HistoryOsmPrimitive primitive, int earliestVersion) {
-            this.modificationType = modificationType;
-            this.primitive = primitive;
-            this.earliestVersion = earliestVersion;
-        }
-
-        @Override
-        public ChangesetModificationType getModificationType() {
-            return modificationType;
-        }
-
-        @Override
-        public HistoryOsmPrimitive getPrimitive() {
-            return primitive;
-        }
-
-        @Override
-        public int getEarliestVersion() {
-            return earliestVersion;
-        }
-}
-
-    private class DefaultIterator implements Iterator<ChangesetDataSetEntry> {
-        private final Iterator<Entry<PrimitiveId, ChangesetModificationType>> typeIterator;
-
-        DefaultIterator() {
-            typeIterator = modificationTypes.entrySet().iterator();
-        }
-
-        @Override
-        public boolean hasNext() {
-            return typeIterator.hasNext();
-        }
-
-        @Override
-        public ChangesetDataSetEntry next() {
-            Entry<PrimitiveId, ChangesetModificationType> next = typeIterator.next();
-            ChangesetModificationType type = next.getValue();
-            HistoryOsmPrimitive primitive = primitives.get(next.getKey());
-            Integer earliestVersion = earliestVersions.get(next.getKey());
-            if (earliestVersion == null) earliestVersion = (int) primitive.getVersion();
-            return new DefaultChangesetDataSetEntry(type, primitive, earliestVersion);
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-}
Index: src/reverter/corehacks/OsmChangesetContentParser.java
===================================================================
--- src/reverter/corehacks/OsmChangesetContentParser.java	(revision 34950)
+++ src/reverter/corehacks/OsmChangesetContentParser.java	(nonexistent)
@@ -1,342 +0,0 @@
-// License: GPL. For details, see LICENSE file.
-package reverter.corehacks;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.util.Date;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
-import org.openstreetmap.josm.data.osm.RelationMemberData;
-import org.openstreetmap.josm.data.osm.User;
-import org.openstreetmap.josm.data.osm.history.HistoryNode;
-import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
-import org.openstreetmap.josm.data.osm.history.HistoryRelation;
-import org.openstreetmap.josm.data.osm.history.HistoryWay;
-import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.tools.CheckParameterUtil;
-import org.openstreetmap.josm.tools.XmlParsingException;
-import org.openstreetmap.josm.tools.date.DateUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import reverter.corehacks.ChangesetDataSet.ChangesetModificationType;
-
-/**
- * Parser for OSM changeset content.
- *
- */
-public class OsmChangesetContentParser {
-
-    private final InputSource source;
-    private final ChangesetDataSet data;
-
-    private class Parser extends DefaultHandler {
-
-        /** the current primitive to be read */
-        private HistoryOsmPrimitive currentPrimitive;
-        /** the current change modification type */
-        private ChangesetDataSet.ChangesetModificationType currentModificationType;
-
-        private Locator locator;
-
-        @Override
-        public void setDocumentLocator(Locator locator) {
-            this.locator = locator;
-        }
-
-        protected void throwException(String message) throws XmlParsingException {
-            throw new XmlParsingException(
-                    message
-            ).rememberLocation(locator);
-        }
-
-        protected void throwException(Exception e) throws XmlParsingException {
-            throw new XmlParsingException(
-                    e
-            ).rememberLocation(locator);
-        }
-
-        protected long getMandatoryAttributeLong(Attributes attr, String name) throws SAXException {
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            Long l = 0L;
-            try {
-                l = Long.parseLong(v);
-            } catch (NumberFormatException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long. Got ''{1}''.", name, v));
-            }
-            if (l < 0) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
-            }
-            return l;
-        }
-/*
-        protected long getAttributeLong(Attributes attr, String name, long defaultValue) throws SAXException{
-            String v = attr.getValue(name);
-            if (v == null)
-                return defaultValue;
-            Long l = 0l;
-            try {
-                l = Long.parseLong(v);
-            } catch(NumberFormatException e) {
-                throwException(tr("Illegal value for attribute ''{0}'' of type long. Got ''{1}''.", name, v));
-            }
-            if (l < 0) {
-                throwException(tr("Illegal value for attribute ''{0}'' of type long (>=0). Got ''{1}''.", name, v));
-            }
-            return l;
-        }
-*/
-
-        protected Double getAttributeDouble(Attributes attr, String name) throws SAXException {
-            String v = attr.getValue(name);
-            if (v == null) {
-                return null;
-            }
-            double d = 0.0;
-            try {
-                d = Double.parseDouble(v);
-            } catch (NumberFormatException e) {
-                throwException(tr("Illegal value for attribute ''{0}'' of type double. Got ''{1}''.", name, v));
-            }
-            return d;
-        }
-
-        protected String getMandatoryAttributeString(Attributes attr, String name) throws SAXException {
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            return v;
-        }
-/*
-        protected String getAttributeString(Attributes attr, String name, String defaultValue) {
-            String v = attr.getValue(name);
-            if (v == null)
-                return defaultValue;
-            return v;
-        }
-*/
-
-        protected boolean getMandatoryAttributeBoolean(Attributes attr, String name) throws SAXException {
-            String v = attr.getValue(name);
-            if (v == null) {
-                throwException(tr("Missing mandatory attribute ''{0}''.", name));
-            }
-            if ("true".equals(v)) return true;
-            if ("false".equals(v)) return false;
-            throwException(tr("Illegal value for mandatory attribute ''{0}'' of type boolean. Got ''{1}''.", name, v));
-            // not reached
-            return false;
-        }
-
-        protected HistoryOsmPrimitive createPrimitive(Attributes atts, OsmPrimitiveType type) throws SAXException {
-            long id = getMandatoryAttributeLong(atts, "id");
-            long version = getMandatoryAttributeLong(atts, "version");
-            long changesetId = getMandatoryAttributeLong(atts, "changeset");
-            boolean visible = getMandatoryAttributeBoolean(atts, "visible");
-            String v = getMandatoryAttributeString(atts, "timestamp");
-            Date timestamp = DateUtils.fromString(v);
-            HistoryOsmPrimitive primitive = null;
-            // Hack: reverter doesn't need user information, so always use User.getAnonymous()
-            // TODO: Update OsmChangesetContentParser from the core or update core OsmChangesetContentParser to make it usable with reverter
-            if (type.equals(OsmPrimitiveType.NODE)) {
-                Double lat = getAttributeDouble(atts, "lat");
-                Double lon = getAttributeDouble(atts, "lon");
-                LatLon coor = (lat != null && lon != null) ? new LatLon(lat, lon) : null;
-                primitive = new HistoryNode(
-                        id, version, visible, User.getAnonymous(), changesetId, timestamp, coor
-                );
-
-            } else if (type.equals(OsmPrimitiveType.WAY)) {
-                primitive = new HistoryWay(
-                        id, version, visible, User.getAnonymous(), changesetId, timestamp
-                );
-            } else if (type.equals(OsmPrimitiveType.RELATION)) {
-                primitive = new HistoryRelation(
-                        id, version, visible, User.getAnonymous(), changesetId, timestamp
-                );
-            }
-            return primitive;
-        }
-
-        protected void startNode(Attributes atts) throws SAXException {
-            currentPrimitive = createPrimitive(atts, OsmPrimitiveType.NODE);
-        }
-
-        protected void startWay(Attributes atts) throws SAXException {
-            currentPrimitive = createPrimitive(atts, OsmPrimitiveType.WAY);
-        }
-
-        protected void startRelation(Attributes atts) throws SAXException {
-            currentPrimitive = createPrimitive(atts, OsmPrimitiveType.RELATION);
-        }
-
-        protected void handleTag(Attributes atts) throws SAXException {
-            String key = getMandatoryAttributeString(atts, "k");
-            String value = getMandatoryAttributeString(atts, "v");
-            currentPrimitive.put(key, value);
-        }
-
-        protected void handleNodeReference(Attributes atts) throws SAXException {
-            long ref = getMandatoryAttributeLong(atts, "ref");
-            ((HistoryWay) currentPrimitive).addNode(ref);
-        }
-
-        protected void handleMember(Attributes atts) throws SAXException {
-            long ref = getMandatoryAttributeLong(atts, "ref");
-            String v = getMandatoryAttributeString(atts, "type");
-            OsmPrimitiveType type = null;
-            try {
-                type = OsmPrimitiveType.fromApiTypeName(v);
-            } catch (IllegalArgumentException e) {
-                throwException(tr("Illegal value for mandatory attribute ''{0}'' of type OsmPrimitiveType. Got ''{1}''.", "type", v));
-            }
-            String role = getMandatoryAttributeString(atts, "role");
-            RelationMemberData member = new RelationMemberData(role, type, ref);
-            ((HistoryRelation) currentPrimitive).addMember(member);
-        }
-
-        @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
-            if (qName.equals("node")) {
-                startNode(atts);
-            } else if (qName.equals("way")) {
-                startWay(atts);
-            } else if (qName.equals("relation")) {
-                startRelation(atts);
-            } else if (qName.equals("tag")) {
-                handleTag(atts);
-            } else if (qName.equals("nd")) {
-                handleNodeReference(atts);
-            } else if (qName.equals("member")) {
-                handleMember(atts);
-            } else if (qName.equals("osmChange")) {
-                // do nothing
-            } else if (qName.equals("create")) {
-                currentModificationType = ChangesetModificationType.CREATED;
-            } else if (qName.equals("modify")) {
-                currentModificationType = ChangesetModificationType.UPDATED;
-            } else if (qName.equals("delete")) {
-                currentModificationType = ChangesetModificationType.DELETED;
-            } else {
-                System.err.println(tr("Warning: unsupported start element ''{0}'' in changeset content at position ({1},{2}). Skipping.",
-                        qName, locator.getLineNumber(), locator.getColumnNumber()));
-            }
-        }
-
-        @Override
-        public void endElement(String uri, String localName, String qName) throws SAXException {
-            if (qName.equals("node")
-                    || qName.equals("way")
-                    || qName.equals("relation")) {
-                if (currentModificationType == null) {
-                    throwException(
-                            tr("Illegal document structure. Found node, way, or relation outside of ''create'', ''modify'', or ''delete''."));
-                }
-                data.put(currentPrimitive, currentModificationType);
-            } else if (qName.equals("osmChange")) {
-                // do nothing
-            } else if (qName.equals("create")) {
-                currentModificationType = null;
-            } else if (qName.equals("modify")) {
-                currentModificationType = null;
-            } else if (qName.equals("delete")) {
-                currentModificationType = null;
-            } else if (qName.equals("tag")) {
-                // do nothing
-            } else if (qName.equals("nd")) {
-                // do nothing
-            } else if (qName.equals("member")) {
-                // do nothing
-            } else {
-                System.err.println(tr("Warning: unsupported end element ''{0}'' in changeset content at position ({1},{2}). Skipping.",
-                        qName, locator.getLineNumber(), locator.getColumnNumber()));
-            }
-        }
-
-        @Override
-        public void error(SAXParseException e) throws SAXException {
-            throwException(e);
-        }
-
-        @Override
-        public void fatalError(SAXParseException e) throws SAXException {
-            throwException(e);
-        }
-    }
-
-    /**
-     * Create a parser
-     *
-     * @param source the input stream with the changeset content as XML document. Must not be null.
-     * @throws IllegalArgumentException thrown if source is null.
-     * @throws UnsupportedEncodingException if the named charset is not supported
-     */
-    public OsmChangesetContentParser(InputStream source) throws UnsupportedEncodingException {
-        CheckParameterUtil.ensureParameterNotNull(source, "source");
-        this.source = new InputSource(new InputStreamReader(source, "UTF-8"));
-        data = new ChangesetDataSet();
-    }
-
-    public OsmChangesetContentParser(String source) {
-        CheckParameterUtil.ensureParameterNotNull(source, "source");
-        this.source = new InputSource(new StringReader(source));
-        data = new ChangesetDataSet();
-    }
-
-    /**
-     * Parses the content
-     *
-     * @param progressMonitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE}
-     * if null
-     * @return the parsed data
-     * @throws XmlParsingException if something went wrong. Check for chained exceptions.
-     */
-    public ChangesetDataSet parse(ProgressMonitor progressMonitor) throws XmlParsingException {
-        if (progressMonitor == null) {
-            progressMonitor = NullProgressMonitor.INSTANCE;
-        }
-        try {
-            progressMonitor.beginTask("");
-            progressMonitor.indeterminateSubTask(tr("Parsing changeset content ..."));
-            SAXParserFactory.newInstance().newSAXParser().parse(source, new Parser());
-        } catch (XmlParsingException e) {
-            throw e;
-        } catch (ParserConfigurationException e) {
-            throw new XmlParsingException(e);
-        } catch (SAXException e) {
-            throw new XmlParsingException(e);
-        } catch (IOException e) {
-            throw new XmlParsingException(e);
-        } finally {
-            progressMonitor.finishTask();
-        }
-        return data;
-    }
-
-    /**
-     * Parses the content from the input source
-     *
-     * @return the parsed data
-     * @throws XmlParsingException if something went wrong. Check for chained exceptions.
-     */
-    public ChangesetDataSet parse() throws XmlParsingException {
-        return parse(null);
-    }
-}
Index: src/reverter/corehacks/OsmServerChangesetReader.java
===================================================================
--- src/reverter/corehacks/OsmServerChangesetReader.java	(revision 34950)
+++ src/reverter/corehacks/OsmServerChangesetReader.java	(nonexistent)
@@ -1,200 +0,0 @@
-// License: GPL. For details, see LICENSE file.
-package reverter.corehacks;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-import static org.openstreetmap.josm.tools.I18n.trn;
-
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import org.openstreetmap.josm.data.osm.Changeset;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.ChangesetQuery;
-import org.openstreetmap.josm.io.IllegalDataException;
-import org.openstreetmap.josm.io.OsmChangesetParser;
-import org.openstreetmap.josm.io.OsmServerReader;
-import org.openstreetmap.josm.io.OsmTransferException;
-import org.openstreetmap.josm.tools.CheckParameterUtil;
-import org.openstreetmap.josm.tools.XmlParsingException;
-
-/**
- * Reads the history of an {@link OsmPrimitive} from the OSM API server.
- *
- */
-public class OsmServerChangesetReader extends OsmServerReader {
-
-    /**
-     * constructor
-     *
-     */
-    public OsmServerChangesetReader() {
-        setDoAuthenticate(false);
-    }
-
-    /**
-     * don't use - not implemented!
-     *
-     */
-    @Override
-    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
-        return null;
-    }
-
-    /**
-     * Queries a list
-     * @param query  the query specification. Must not be null.
-     * @param monitor a progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
-     * @return the list of changesets read from the server or {@code null}
-     * @throws IllegalArgumentException thrown if query is null
-     * @throws OsmTransferException thrown if something goes wrong w
-     */
-    public List<Changeset> queryChangesets(ChangesetQuery query, ProgressMonitor monitor) throws OsmTransferException {
-        CheckParameterUtil.ensureParameterNotNull(query, "query");
-        if (monitor == null) {
-            monitor = NullProgressMonitor.INSTANCE;
-        }
-        try {
-            monitor.beginTask(tr("Reading changesets..."));
-            StringBuilder sb = new StringBuilder();
-            sb.append("changesets?").append(query.getQueryString());
-            InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
-            if (in == null)
-                return null;
-            monitor.indeterminateSubTask(tr("Downloading changesets ..."));
-            return OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
-        } catch (OsmTransferException e) {
-            throw e;
-        } catch (IllegalDataException e) {
-            throw new OsmTransferException(e);
-        } finally {
-            monitor.finishTask();
-        }
-    }
-
-    /**
-     * Reads the changeset with id <code>id</code> from the server
-     *
-     * @param id  the changeset id. id &gt; 0 required.
-     * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
-     * @return the changeset read
-     * @throws OsmTransferException thrown if something goes wrong
-     * @throws IllegalArgumentException if id &lt;= 0
-     */
-    public Changeset readChangeset(long id, ProgressMonitor monitor) throws OsmTransferException {
-        if (id <= 0)
-            throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected. Got ''{1}''.", "id", id));
-        if (monitor == null) {
-            monitor = NullProgressMonitor.INSTANCE;
-        }
-        try {
-            monitor.beginTask(tr("Reading changeset {0} ...", id));
-            StringBuilder sb = new StringBuilder();
-            sb.append("changeset/").append(id);
-            InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
-            if (in == null)
-                return null;
-            monitor.indeterminateSubTask(tr("Downloading changeset {0} ...", id));
-            List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
-            if (changesets == null || changesets.isEmpty())
-                return null;
-            return changesets.get(0);
-        } catch (OsmTransferException e) {
-            throw e;
-        } catch (IllegalDataException e) {
-            throw new OsmTransferException(e);
-        } finally {
-            monitor.finishTask();
-        }
-    }
-
-    /**
-     * Reads the changeset with id <code>id</code> from the server
-     *
-     * @param ids  the collection of ids. Ignored if null. Only load changesets for ids &gt; 0.
-     * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
-     * @return the list of changesets read or an empty list or null in case of errors
-     * @throws OsmTransferException thrown if something goes wrong
-     * @throws IllegalArgumentException if id &lt;= 0
-     */
-    public List<Changeset> readChangesets(Collection<Integer> ids, ProgressMonitor monitor) throws OsmTransferException {
-        if (ids == null)
-            return Collections.emptyList();
-        if (monitor == null) {
-            monitor = NullProgressMonitor.INSTANCE;
-        }
-        try {
-            monitor.beginTask(trn("Downloading {0} changeset ...", "Downloading {0} changesets ...", ids.size(), ids.size()));
-            monitor.setTicksCount(ids.size());
-            List<Changeset> ret = new ArrayList<>();
-            int i = 0;
-            for (Iterator<Integer> it = ids.iterator(); it.hasNext();) {
-                int id = it.next();
-                if (id <= 0) {
-                    continue;
-                }
-                i++;
-                StringBuilder sb = new StringBuilder();
-                sb.append("changeset/").append(id);
-                InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
-                if (in == null)
-                    return null;
-                monitor.indeterminateSubTask(tr("({0}/{1}) Downloading changeset {2}...", i, ids.size(), id));
-                List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
-                if (changesets == null || changesets.isEmpty()) {
-                    continue;
-                }
-                ret.addAll(changesets);
-                monitor.worked(1);
-            }
-            return ret;
-        } catch (OsmTransferException e) {
-            throw e;
-        } catch (IllegalDataException e) {
-            throw new OsmTransferException(e);
-        } finally {
-            monitor.finishTask();
-        }
-    }
-
-    /**
-     * Downloads the content of a changeset
-     *
-     * @param id the changeset id. &gt;0 required.
-     * @param monitor the progress monitor. {@link NullProgressMonitor#INSTANCE} assumed if null.
-     * @return the changeset content
-     * @throws IllegalArgumentException thrown if id &lt;= 0
-     * @throws OsmTransferException thrown if something went wrong
-     */
-    public ChangesetDataSet downloadChangeset(int id, ProgressMonitor monitor) throws OsmTransferException {
-        if (id <= 0)
-            throw new IllegalArgumentException(
-                    MessageFormat.format("Expected value of type integer > 0 for parameter ''{0}'', got {1}", "id", id));
-        if (monitor == null) {
-            monitor = NullProgressMonitor.INSTANCE;
-        }
-        try {
-            monitor.beginTask(tr("Downloading changeset content"));
-            StringBuilder sb = new StringBuilder();
-            sb.append("changeset/").append(id).append("/download");
-            InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
-            if (in == null)
-                return null;
-            monitor.setCustomText(tr("Downloading content for changeset {0} ...", id));
-            OsmChangesetContentParser parser = new OsmChangesetContentParser(in);
-            return parser.parse(monitor.createSubTaskMonitor(1, true));
-        } catch (UnsupportedEncodingException | XmlParsingException e) {
-            throw new OsmTransferException(e);
-        } finally {
-            monitor.finishTask();
-        }
-    }
-}
