Index: /src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmReader.java	(revision 59)
+++ /src/org/openstreetmap/josm/io/OsmReader.java	(revision 59)
@@ -0,0 +1,119 @@
+package org.openstreetmap.josm.io;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Key;
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Track;
+import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import uk.co.wilson.xml.MinML2;
+
+/**
+ * Parser for the Osm Api. Read from an input stream and construct a dataset out of it.
+ * 
+ * @author Imi
+ */
+public class OsmReader extends MinML2 {
+
+	/**
+	 * The dataset to add parsed objects to.
+	 */
+	private DataSet ds = new DataSet();
+
+	/**
+	 * The visitor to use to add the data to the set.
+	 */
+	private AddVisitor adder = new AddVisitor(ds);
+	
+	/**
+	 * The current processed primitive.
+	 */
+	private OsmPrimitive current;
+
+	/**
+	 * All read nodes so far.
+	 */
+	private Map<Long, Node> nodes = new HashMap<Long, Node>();
+	/**
+	 * All read segents so far.
+	 */
+	private Map<Long, LineSegment> lineSegments = new HashMap<Long, LineSegment>();
+	
+	/**
+	 * Parse the given input source and return the dataset.
+	 */
+	public static DataSet parseDataSet(Reader source) throws SAXException, IOException {
+		OsmReader osm = new OsmReader(source);
+
+		// clear all negative ids (new to this file)
+		for (OsmPrimitive o : osm.ds.allPrimitives())
+			if (o.id < 0)
+				o.id = 0;
+		
+		return osm.ds;
+	}
+
+	private OsmReader(Reader source) throws SAXException, IOException {
+		parse(source);
+	}
+
+	@Override
+	public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+		try {
+			if (qName.equals("osm")) {
+				if (atts == null)
+					throw new SAXException("Unknown version.");
+				if (!"0.3".equals(atts.getValue("version")))
+					throw new SAXException("Unknown version: "+atts.getValue("version"));
+			} else if (qName.equals("node")) {
+				Node n = new Node();
+				n.coor = new GeoPoint(getDouble(atts, "lat"), getDouble(atts, "lon"));
+				current = n;
+				current.id = getLong(atts, "id");
+				nodes.put(n.id, n);
+			} else if (qName.equals("segment")) {
+				current = new LineSegment(
+						nodes.get(getLong(atts, "from")), 
+						nodes.get(getLong(atts, "to")));
+				current.id = getLong(atts, "id");
+				lineSegments.put(current.id, (LineSegment)current);
+			} else if (qName.equals("way")) {
+				current = new Track();
+				current.id = getLong(atts, "id");
+			} else if (qName.equals("seg")) {
+				if (current instanceof Track)
+					((Track)current).segments.add(lineSegments.get(getLong(atts, "id")));
+			} else if (qName.equals("tag")) {
+				current.put(Key.get(atts.getValue("k")), atts.getValue("v"));
+			}
+		} catch (NumberFormatException x) {
+			throw new SAXException(x.getMessage(), x);
+		} catch (NullPointerException x) {
+			throw new SAXException("NullPointerException. Possible some missing tags.", x);
+		}
+	}
+
+	@Override
+	public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
+		if (qName.equals("node") || qName.equals("segment") || qName.equals("way") || qName.equals("area")) {
+			current.visit(adder);
+		}
+	}
+
+	private double getDouble(Attributes atts, String value) {
+		return Double.parseDouble(atts.getValue(value));
+	}
+	private long getLong(Attributes atts, String value) {
+		return Long.parseLong(atts.getValue(value));
+	}
+}
Index: /src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 59)
+++ /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 59)
@@ -0,0 +1,142 @@
+package org.openstreetmap.josm.io;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Key;
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Track;
+import org.openstreetmap.josm.data.osm.visitor.Visitor;
+
+/**
+ * Save the dataset into a stream as osm intern xml format. This is not using any
+ * xml library for storing.
+ * @author imi
+ */
+public class OsmWriter implements Visitor {
+
+	/**
+	 * The output writer to save the values to.
+	 */
+	private PrintWriter out;
+
+	/**
+	 * The counter for new created objects. Starting at -1 and goes down.
+	 */
+	private long newIdCounter = -1;
+	/**
+	 * All newly created ids and their primitive that uses it. This is a back reference
+	 * map to allow references to use the correnct primitives.
+	 */
+	private HashMap<OsmPrimitive, Long> usedNewIds = new HashMap<OsmPrimitive, Long>();
+
+	private final boolean osmConform;
+
+	/**
+	 * Output the data to the stream
+	 * @param osmConform <code>true</code>, if the xml should be 100% osm conform. In this
+	 * 		case, not all information can be retrieved later (as example, modified state
+	 * 		is lost and id's remain 0 instead of decrementing from -1)
+	 */
+	public static void output(Writer out, DataSet ds, boolean osmConform) {
+		OsmWriter writer = new OsmWriter(out, osmConform);
+		writer.out.println("<osm version='0.3' generator='JOSM'>");
+		for (Node n : ds.nodes)
+			writer.visit(n);
+		for (LineSegment ls : ds.lineSegments)
+			writer.visit(ls);
+		for (Track w : ds.tracks)
+			writer.visit(w);
+		writer.out.println("</osm>");
+	}
+
+	public static void outputSingle(Writer out, OsmPrimitive osm, boolean osmConform) {
+		OsmWriter writer = new OsmWriter(out, osmConform);
+		writer.out.println("<osm version='0.3' generator='JOSM'>");
+		osm.visit(writer);
+		writer.out.println("</osm>");
+	}
+	
+	private OsmWriter(Writer out, boolean osmConform) {
+		if (out instanceof PrintWriter)
+			this.out = (PrintWriter)out;
+		else
+			this.out = new PrintWriter(out);
+		this.osmConform = osmConform;
+	}
+	
+	public void visit(Node n) {
+		addCommon(n, "node");
+		out.print(" lat='"+n.coor.lat+"' lon='"+n.coor.lon+"'");
+		addTags(n, "node", true);
+	}
+
+	public void visit(LineSegment ls) {
+		addCommon(ls, "segment");
+		out.print(" from='"+getUsedId(ls.start)+"' to='"+getUsedId(ls.end)+"'");
+		addTags(ls, "segment", true);
+	}
+
+	public void visit(Track w) {
+		addCommon(w, "way");
+		out.println(">");
+		for (LineSegment ls : w.segments)
+			out.println("    <seg id='"+getUsedId(ls)+"' />");
+		addTags(w, "way", false);
+	}
+
+	public void visit(Key k) {
+	}
+
+	/**
+	 * Return the id for the given osm primitive (may access the usedId map)
+	 */
+	private long getUsedId(OsmPrimitive osm) {
+		if (osm.id != 0)
+			return osm.id;
+		if (usedNewIds.containsKey(osm))
+			return usedNewIds.get(osm);
+		usedNewIds.put(osm, newIdCounter);
+		return osmConform ? 0 : newIdCounter--;
+	}
+
+
+	private void addTags(OsmPrimitive osm, String tagname, boolean tagOpen) {
+		if (osm.keys != null) {
+			if (tagOpen)
+				out.println(">");
+			for (Entry<Key, String> e : osm.keys.entrySet())
+				out.println("    <tag k='"+e.getKey().name+"' v='"+e.getValue()+"' />");
+			out.println("  </"+tagname+">");
+		} else if (tagOpen)
+			out.println(" />");
+		else
+			out.println("  </"+tagname+">");
+	}
+
+	/**
+	 * Add the common part as the start of the tag as well as the id or the action tag.
+	 */
+	private void addCommon(OsmPrimitive osm, String tagname) {
+		out.print("  <"+tagname+" id='"+getUsedId(osm)+"'");
+		if (!osmConform) {
+			String action = null;
+			if (osm.isDeleted())
+				action = "delete";
+			else if (osm.modified && osm.modifiedProperties)
+				action = "modify";
+			else if (osm.modified && !osm.modifiedProperties)
+				action = "modify/object";
+			else if (!osm.modified && osm.modifiedProperties)
+				action = "modify/property";
+			if (action != null)
+				out.print(" action='"+action+"'");
+		}
+	}
+}
+
