From 2112ee04f0d7379082b874b0c6d7049f4743bd77 Mon Sep 17 00:00:00 2001
From: Jason Long <jason@long.name>
Date: Tue, 17 Jun 2014 15:24:14 -0400
Subject: [PATCH] MakeTiles: change format of tiles.idx (preparing for future
 capability)

---
 src/micropolisj/XML_Helper.java           | 137 ++++++++++++++++++++++
 src/micropolisj/build_tool/MakeTiles.java |   2 +
 src/micropolisj/gui/TileImages.java       |  22 ++--
 3 files changed, 154 insertions(+), 7 deletions(-)
 create mode 100644 src/micropolisj/XML_Helper.java

diff --git a/src/micropolisj/XML_Helper.java b/src/micropolisj/XML_Helper.java
new file mode 100644
index 0000000..3980d1c
--- /dev/null
+++ b/src/micropolisj/XML_Helper.java
@@ -0,0 +1,137 @@
+package micropolisj;
+
+import java.io.*;
+import javax.xml.stream.*;
+
+public class XML_Helper
+{
+	private XML_Helper() {}
+
+	public static void skipToEndElement(XMLStreamReader in)
+		throws XMLStreamException
+	{
+		if (!in.isStartElement()) {
+			return;
+		}
+
+		int tagDepth = 1;
+		while (tagDepth > 0 && in.hasNext()) {
+			in.next();
+			if (in.isStartElement()) {
+				tagDepth++;
+			}
+			else if (in.isEndElement()) {
+				tagDepth--;
+			}
+		}
+	}
+
+	public static Reader readElementText(XMLStreamReader in)
+	{
+		return new ElementTextReader(in);
+	}
+
+	static class ElementTextReader extends Reader
+	{
+		XMLStreamReader xsr;
+		int tagDepth;
+		char [] buf;
+		int buf_start;
+		int buf_end;
+
+		ElementTextReader(XMLStreamReader xsr)
+		{
+			this.xsr = xsr;
+			this.tagDepth = 1;
+		}
+
+		private void readMore()
+			throws XMLStreamException
+		{
+			while (tagDepth > 0 && buf_start == buf_end) {
+
+				int nodeType = xsr.next();
+				if (nodeType == XMLStreamConstants.START_ELEMENT) {
+					tagDepth++;
+				}
+				else if (nodeType == XMLStreamConstants.END_ELEMENT) {
+					tagDepth--;
+				}
+				else if (nodeType == XMLStreamConstants.CDATA ||
+					nodeType == XMLStreamConstants.CHARACTERS ||
+					nodeType == XMLStreamConstants.ENTITY_REFERENCE ||
+					nodeType == XMLStreamConstants.SPACE)
+				{
+					buf = xsr.getTextCharacters();
+					buf_start = xsr.getTextStart();
+					buf_end = buf_start + xsr.getTextLength();
+				}
+			}
+	
+		}
+
+		@Override
+		public int read(char[] cbuf, int off, int len)
+			throws IOException
+		{
+			if (buf_start == buf_end) {
+
+				try {
+					readMore();
+				}
+				catch (XMLStreamException e) {
+					throw new IOException("XML stream error: "+ e, e);
+				}
+
+				if (tagDepth == 0) {
+					// reached closing tag
+					return -1;
+				}
+			}
+
+			if (buf_start + len <= buf_end) {
+				// already have the text loaded
+				System.arraycopy(buf, buf_start, cbuf, off, len);
+				buf_start += len;
+				return len;
+			}
+			else {
+				// not enough text available for entire request,
+				// so just return what we have until the next
+				// request
+
+				len = buf_end - buf_start;
+				assert len > 0;
+
+				System.arraycopy(buf, buf_start, cbuf, off, len);
+				buf_start += len;
+				assert buf_start == buf_end;
+				return len;
+			}
+		}
+
+		@Override
+		public void close()
+			throws IOException
+		{
+			buf_start = 0;
+			buf_end = 0;
+
+			try {
+
+			while (tagDepth > 0 && xsr.hasNext()) {
+				xsr.next();
+				if (xsr.isStartElement()) {
+					tagDepth++;
+				}
+				else if (xsr.isEndElement()) {
+					tagDepth--;
+				}
+			}
+			}
+			catch (XMLStreamException e) {
+				throw new IOException("XML stream error: "+e, e);
+			}
+		}
+	}
+}
diff --git a/src/micropolisj/build_tool/MakeTiles.java b/src/micropolisj/build_tool/MakeTiles.java
index bcc4c3b..33ae818 100644
--- a/src/micropolisj/build_tool/MakeTiles.java
+++ b/src/micropolisj/build_tool/MakeTiles.java
@@ -111,8 +111,10 @@ public class MakeTiles
 		for (int i = 0; i < tileNames.length; i++) {
 			out.writeStartElement("tile");
 			out.writeAttribute("name", tileNames[i]);
+			out.writeStartElement("image");
 			out.writeAttribute("offsetY", Integer.toString(i));
 			out.writeEndElement();
+			out.writeEndElement();
 		}
 		out.writeEndElement();
 		out.writeEndDocument();
diff --git a/src/micropolisj/gui/TileImages.java b/src/micropolisj/gui/TileImages.java
index bc1a028..05a5140 100644
--- a/src/micropolisj/gui/TileImages.java
+++ b/src/micropolisj/gui/TileImages.java
@@ -18,6 +18,7 @@ import javax.xml.stream.*;
 
 import micropolisj.engine.*;
 import static micropolisj.engine.TileConstants.*;
+import static micropolisj.XML_Helper.*;
 
 public class TileImages
 {
@@ -60,19 +61,26 @@ public class TileImages
 			throw new IOException("Unrecognized file format");
 		}
 
-		while (in.next() != XMLStreamConstants.END_ELEMENT) {
-			if (!in.isStartElement()) {
-				continue;
-			}
+		while (in.nextTag() != XMLStreamConstants.END_ELEMENT) {
+			assert in.isStartElement();
 
 			String tagName = in.getLocalName();
 			if (!tagName.equals("tile")) {
-				in.next();
+				skipToEndElement(in);
 				continue;
 			}
 
 			String tileName = in.getAttributeValue(null, "name");
-			int imageNumber = Integer.parseInt(in.getAttributeValue(null, "offsetY"));
+			int imageNumber = -1;
+
+			while (in.nextTag() != XMLStreamConstants.END_ELEMENT) {
+				assert in.isStartElement();
+				if (in.getLocalName().equals("image")) {
+					String tmp = in.getAttributeValue(null, "offsetY");
+					imageNumber = tmp != null ? Integer.parseInt(tmp) : 0;
+				}
+				skipToEndElement(in);
+			}
 
 			assert tileName != null;
 			assert imageNumber >= 0 && imageNumber < images.length;
@@ -80,7 +88,7 @@ public class TileImages
 			TileSpec ts = Tiles.load(tileName);
 			tileImageMap[ts.tileNumber] = imageNumber;
 
-			in.next();
+			assert in.isEndElement() && in.getLocalName().equals("tile");
 		}
 
 		in.close();