diff --git a/api/net/sf/briar/api/serial/FormatRuntimeException.java b/api/net/sf/briar/api/serial/FormatRuntimeException.java
deleted file mode 100644
index 5b855bc03e986b4b9a524ce3cbe9e5533b50fa64..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/serial/FormatRuntimeException.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package net.sf.briar.api.serial;
-
-public class FormatRuntimeException extends RuntimeException {
-
-	private static final long serialVersionUID = -6548900875808933998L;
-}
diff --git a/api/net/sf/briar/api/serial/Reader.java b/api/net/sf/briar/api/serial/Reader.java
index 652cd94d3dffb99333df20078e4610f14c1cf349..3a92c90a16f1c4e18709c1bfe292669e73f05b41 100644
--- a/api/net/sf/briar/api/serial/Reader.java
+++ b/api/net/sf/briar/api/serial/Reader.java
@@ -1,14 +1,14 @@
 package net.sf.briar.api.serial;
 
 import java.io.IOException;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 
 public interface Reader {
 
 	boolean eof() throws IOException;
+	void setReadLimit(long limit);
+	void resetReadLimit();
 
 	boolean hasBoolean() throws IOException;
 	boolean readBoolean() throws IOException;
@@ -33,23 +33,24 @@ public interface Reader {
 
 	boolean hasUtf8() throws IOException;
 	String readUtf8() throws IOException;
-	String readUtf8(int maxLength) throws IOException;
-
 	boolean hasRaw() throws IOException;
 	byte[] readRaw() throws IOException;
-	byte[] readRaw(int maxLength) throws IOException;
 
 	boolean hasList() throws IOException;
 	List<Object> readList() throws IOException;
-	Iterator<Object> readListElements() throws IOException;
 	<E> List<E> readList(Class<E> e) throws IOException;
-	<E> Iterator<E> readListElements(Class<E> e) throws IOException;
+	boolean hasListStart() throws IOException;
+	void readListStart() throws IOException;
+	boolean hasListEnd() throws IOException;
+	void readListEnd() throws IOException;
 
 	boolean hasMap() throws IOException;
 	Map<Object, Object> readMap() throws IOException;
-	Iterator<Entry<Object, Object>> readMapEntries() throws IOException;
 	<K, V> Map<K, V> readMap(Class<K> k, Class<V> v) throws IOException;
-	<K, V> Iterator<Entry<K, V>> readMapEntries(Class<K> k, Class<V> v) throws IOException;
+	boolean hasMapStart() throws IOException;
+	void readMapStart() throws IOException;
+	boolean hasMapEnd() throws IOException;
+	void readMapEnd() throws IOException;
 
 	boolean hasNull() throws IOException;
 	void readNull() throws IOException;
diff --git a/api/net/sf/briar/api/serial/Tag.java b/api/net/sf/briar/api/serial/Tag.java
index f133aaa161e0ac0dd0206fe38f45e5a920187f53..dc2b1cfcb2346f5ac365a6c998e4693319de7d13 100644
--- a/api/net/sf/briar/api/serial/Tag.java
+++ b/api/net/sf/briar/api/serial/Tag.java
@@ -2,7 +2,6 @@ package net.sf.briar.api.serial;
 
 public interface Tag {
 
-	// FIXME: Definite lists and maps
 	public static final byte FALSE = -1, TRUE = -2;
 	public static final byte INT8 = -3, INT16 = -4, INT32 = -5, INT64 = -6;
 	public static final byte FLOAT32 = -7, FLOAT64 = -8;
diff --git a/api/net/sf/briar/api/serial/Writer.java b/api/net/sf/briar/api/serial/Writer.java
index 5ea269eb5a7baf069769bbd971ca6abfb7793bc5..103b8a5f0c12a4103f76cbe4164dd02169aeb1bf 100644
--- a/api/net/sf/briar/api/serial/Writer.java
+++ b/api/net/sf/briar/api/serial/Writer.java
@@ -31,4 +31,6 @@ public interface Writer {
 	void writeMapEnd() throws IOException;
 
 	void writeNull() throws IOException;
+
+	void close() throws IOException;
 }
diff --git a/components/net/sf/briar/serial/ReaderImpl.java b/components/net/sf/briar/serial/ReaderImpl.java
index fbbdba4bd016e22773bc0c6b044ba741bb39cce8..a7043341588b87640b16c98addaeb252a8de958c 100644
--- a/components/net/sf/briar/serial/ReaderImpl.java
+++ b/components/net/sf/briar/serial/ReaderImpl.java
@@ -4,14 +4,10 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
 
 import net.sf.briar.api.serial.FormatException;
-import net.sf.briar.api.serial.FormatRuntimeException;
 import net.sf.briar.api.serial.Reader;
 import net.sf.briar.api.serial.Tag;
 
@@ -20,14 +16,20 @@ class ReaderImpl implements Reader {
 	private static final int TOO_LARGE_TO_KEEP = 4096;
 
 	private final InputStream in;
-	private boolean started = false, eof = false;
+	private boolean started = false, eof = false, readLimited = false;
 	private byte next;
-	private byte[] stringBuffer = null;
+	private long readLimit = 0L;
+	private byte[] buf = null;
 
 	ReaderImpl(InputStream in) {
 		this.in = in;
 	}
 
+	public boolean eof() throws IOException {
+		if(!started) readNext(true);
+		return eof;
+	}
+
 	private byte readNext(boolean eofAcceptable) throws IOException {
 		started = true;
 		int i = in.read();
@@ -40,9 +42,15 @@ class ReaderImpl implements Reader {
 		return next;
 	}
 
-	public boolean eof() throws IOException {
-		if(!started) readNext(true);
-		return eof;
+	public void setReadLimit(long limit) {
+		assert limit >= 0L && limit < Long.MAX_VALUE;
+		readLimited = true;
+		readLimit = limit;
+	}
+
+	public void resetReadLimit() {
+		readLimited = false;
+		readLimit = 0L;
 	}
 
 	public boolean hasBoolean() throws IOException {
@@ -107,17 +115,27 @@ class ReaderImpl implements Reader {
 
 	public int readInt32() throws IOException {
 		if(!hasInt32()) throw new FormatException();
+		readNext(false);
 		return readInt32Bits();
 	}
 
 	private int readInt32Bits() throws IOException {
-		byte b1 = readNext(false);
-		byte b2 = readNext(false);
-		byte b3 = readNext(false);
-		byte b4 = readNext(false);
+		readIntoBuffer(4);
+		return ((buf[0] & 0xFF) << 24) | ((buf[1] & 0xFF) << 16) |
+		((buf[2] & 0xFF) << 8) | (buf[3] & 0xFF);
+	}
+
+	private void readIntoBuffer(int length) throws IOException {
+		assert length > 0;
+		if(buf == null || buf.length < length) buf = new byte[length];
+		buf[0] = next;
+		int offset = 1, read = 0;
+		while(offset < length && read != -1) {
+			read = in.read(buf, offset, length - offset);
+			if(read != -1) offset += read;
+		}
+		if(offset < length) throw new FormatException();
 		readNext(true);
-		return ((b1 & 0xFF) << 24) | ((b2 & 0xFF) << 16) |
-		((b3 & 0xFF) << 8) | (b4 & 0xFF);
 	}
 
 	public boolean hasInt64() throws IOException {
@@ -128,23 +146,16 @@ class ReaderImpl implements Reader {
 
 	public long readInt64() throws IOException {
 		if(!hasInt64()) throw new FormatException();
+		readNext(false);
 		return readInt64Bits();
 	}
 
 	private long readInt64Bits() throws IOException {
-		byte b1 = readNext(false);
-		byte b2 = readNext(false);
-		byte b3 = readNext(false);
-		byte b4 = readNext(false);
-		byte b5 = readNext(false);
-		byte b6 = readNext(false);
-		byte b7 = readNext(false);
-		byte b8 = readNext(false);
-		readNext(true);
-		return ((b1 & 0xFFL) << 56) | ((b2 & 0xFFL) << 48) |
-		((b3 & 0xFFL) << 40) | ((b4 & 0xFFL) << 32) |
-		((b5 & 0xFFL) << 24) | ((b6 & 0xFFL) << 16) |
-		((b7 & 0xFFL) << 8) | (b8 & 0xFFL);
+		readIntoBuffer(8);
+		return ((buf[0] & 0xFFL) << 56) | ((buf[1] & 0xFFL) << 48) |
+		((buf[2] & 0xFFL) << 40) | ((buf[3] & 0xFFL) << 32) |
+		((buf[4] & 0xFFL) << 24) | ((buf[5] & 0xFFL) << 16) |
+		((buf[6] & 0xFFL) << 8) | (buf[7] & 0xFFL);
 	}
 
 	public boolean hasIntAny() throws IOException {
@@ -172,6 +183,7 @@ class ReaderImpl implements Reader {
 
 	public float readFloat32() throws IOException {
 		if(!hasFloat32()) throw new FormatException();
+		readNext(false);
 		return Float.intBitsToFloat(readInt32Bits());
 	}
 
@@ -183,6 +195,7 @@ class ReaderImpl implements Reader {
 
 	public double readFloat64() throws IOException {
 		if(!hasFloat64()) throw new FormatException();
+		readNext(false);
 		return Double.longBitsToDouble(readInt64Bits());
 	}
 
@@ -193,31 +206,26 @@ class ReaderImpl implements Reader {
 	}
 
 	public String readUtf8() throws IOException {
-		return readUtf8(Integer.MAX_VALUE);
-	}
-
-	public String readUtf8(int maxLength) throws IOException {
 		if(!hasUtf8()) throw new FormatException();
 		readNext(false);
 		long l = readIntAny();
-		if(l < 0 || l > maxLength) throw new FormatException();
+		if(l < 0 || l > Integer.MAX_VALUE) throw new FormatException();
 		int length = (int) l;
 		if(length == 0) return "";
-		if(stringBuffer == null || stringBuffer.length < length)
-			stringBuffer = new byte[length];
-		stringBuffer[0] = next;
-		int offset = 1, read = 0;
-		while(offset < length && read != -1) {
-			read = in.read(stringBuffer, offset, length - offset);
-			if(read != -1) offset += read;
-		}
-		if(offset < length) throw new FormatException();
-		String s = new String(stringBuffer, 0, length, "UTF-8");
-		if(length >= TOO_LARGE_TO_KEEP) stringBuffer = null;
-		readNext(true);
+		checkLimit(length);
+		readIntoBuffer(length);
+		String s = new String(buf, 0, length, "UTF-8");
+		if(length >= TOO_LARGE_TO_KEEP) buf = null;
 		return s;
 	}
 
+	private void checkLimit(long bytes) throws FormatException {
+		if(readLimited) {
+			if(bytes > readLimit) throw new FormatException();
+			readLimit -= bytes;
+		}
+	}
+
 	public boolean hasRaw() throws IOException {
 		if(!started) readNext(true);
 		if(eof) return false;
@@ -225,25 +233,16 @@ class ReaderImpl implements Reader {
 	}
 
 	public byte[] readRaw() throws IOException {
-		return readRaw(Integer.MAX_VALUE);
-	}
-
-	public byte[] readRaw(int maxLength) throws IOException {
 		if(!hasRaw()) throw new FormatException();
 		readNext(false);
 		long l = readIntAny();
-		if(l < 0 || l > maxLength) throw new FormatException();
+		if(l < 0 || l > Integer.MAX_VALUE) throw new FormatException();
 		int length = (int) l;
 		if(length == 0) return new byte[] {};
-		byte[] b = new byte[length];
-		b[0] = next;
-		int offset = 1, read = 0;
-		while(offset < length && read != -1) {
-			read = in.read(b, offset, length - offset);
-			if(read != -1) offset += read;
-		}
-		if(offset < length) throw new FormatException();
-		readNext(true);
+		checkLimit(length);
+		readIntoBuffer(length);
+		byte[] b = buf;
+		buf = null;
 		return b;
 	}
 
@@ -257,10 +256,6 @@ class ReaderImpl implements Reader {
 		return readList(Object.class);
 	}
 
-	public Iterator<Object> readListElements() throws IOException {
-		return readListElements(Object.class);
-	}
-
 	public <E> List<E> readList(Class<E> e) throws IOException {
 		if(!hasList()) throw new FormatException();
 		boolean definite = next == Tag.LIST_DEF;
@@ -278,14 +273,6 @@ class ReaderImpl implements Reader {
 		return list;
 	}
 
-	public <E> Iterator<E> readListElements(Class<E> e) throws IOException {
-		if(!hasList()) throw new FormatException();
-		boolean definite = next == Tag.LIST_DEF;
-		readNext(false);
-		if(definite) return new DefiniteListIterator<E>(e);
-		else return new IndefiniteListIterator<E>(e);
-	}
-
 	private boolean hasEnd() throws IOException {
 		if(!started) readNext(true);
 		if(eof) return false;
@@ -293,6 +280,7 @@ class ReaderImpl implements Reader {
 	}
 
 	private void readEnd() throws IOException {
+		if(!started) throw new IllegalStateException();
 		if(!hasEnd()) throw new FormatException();
 		readNext(true);
 	}
@@ -327,6 +315,25 @@ class ReaderImpl implements Reader {
 		}
 	}
 
+	public boolean hasListStart() throws IOException {
+		if(!started) readNext(true);
+		if(eof) return false;
+		return next == Tag.LIST_INDEF;
+	}
+
+	public void readListStart() throws IOException {
+		if(!hasListStart()) throw new FormatException();
+		readNext(false);
+	}
+
+	public boolean hasListEnd() throws IOException {
+		return hasEnd();
+	}
+
+	public void readListEnd() throws IOException {
+		readEnd();
+	}
+
 	public boolean hasMap() throws IOException {
 		if(!started) readNext(true);
 		if(eof) return false;
@@ -337,10 +344,6 @@ class ReaderImpl implements Reader {
 		return readMap(Object.class, Object.class);
 	}
 
-	public Iterator<Entry<Object, Object>> readMapEntries() throws IOException {
-		return readMapEntries(Object.class, Object.class);
-	}
-
 	public <K, V> Map<K, V> readMap(Class<K> k, Class<V> v)	throws IOException {
 		if(!hasMap()) throw new FormatException();
 		boolean definite = next == Tag.MAP_DEF;
@@ -358,194 +361,33 @@ class ReaderImpl implements Reader {
 		return m;
 	}
 
-	public <K, V> Iterator<Entry<K, V>> readMapEntries(Class<K> k, Class<V> v)
-	throws IOException {
-		if(!hasMap()) throw new FormatException();
-		boolean definite = next == Tag.MAP_DEF;
-		readNext(false);
-		if(definite) return new DefiniteMapIterator<K, V>(k, v);
-		else return new IndefiniteMapIterator<K, V>(k, v);
-	}
-
-	public boolean hasNull() throws IOException {
+	public boolean hasMapStart() throws IOException {
 		if(!started) readNext(true);
 		if(eof) return false;
-		return next == Tag.NULL;
+		return next == Tag.MAP_INDEF;
 	}
 
-	public void readNull() throws IOException {
-		if(!hasNull()) throw new FormatException();
-		readNext(true);
+	public void readMapStart() throws IOException {
+		if(!hasMapStart()) throw new FormatException();
+		readNext(false);
 	}
 
-	private class DefiniteListIterator<E> implements Iterator<E> {
-
-		private final Class<E> e;
-		private int remaining;
-
-		private DefiniteListIterator(Class<E> e) throws IOException {
-			this.e = e;
-			long l = readIntAny();
-			if(l < 0 || l > Integer.MAX_VALUE) throw new FormatException();
-			remaining = (int) l;
-		}
-
-		public boolean hasNext() {
-			return remaining > 0;
-		}
-
-		public E next() {
-			if(remaining == 0) throw new NoSuchElementException();
-			remaining--;
-			try {
-				return readObject(e);
-			} catch(FormatException ex) {
-				throw new FormatRuntimeException();
-			} catch(IOException ex) {
-				throw new RuntimeException(ex);
-			}
-		}
-
-		public void remove() {
-			throw new UnsupportedOperationException();
-		}
+	public boolean hasMapEnd() throws IOException {
+		return hasEnd();
 	}
 
-	private class IndefiniteListIterator<E> implements Iterator<E> {
-
-		private final Class<E> e;
-		private boolean hasNext = true;
-
-		private IndefiniteListIterator(Class<E> e) throws IOException {
-			this.e = e;
-			if(hasEnd()) {
-				readEnd();
-				hasNext = false;
-			}
-		}
-
-		public boolean hasNext() {
-			return hasNext;
-		}
-
-		public E next() {
-			if(!hasNext) throw new NoSuchElementException();
-			try {
-				E next = readObject(e);
-				if(hasEnd()) {
-					readEnd();
-					hasNext = false;
-				}
-				return next;
-			} catch(FormatException ex) {
-				throw new FormatRuntimeException();
-			} catch(IOException ex) {
-				throw new RuntimeException(ex);
-			}
-		}
-
-		public void remove() {
-			throw new UnsupportedOperationException();
-		}
+	public void readMapEnd() throws IOException {
+		readEnd();
 	}
 
-	private class DefiniteMapIterator<K, V> implements Iterator<Entry<K, V>> {
-
-		private final Class<K> k;
-		private final Class<V> v;
-		private int remaining;
-
-		private DefiniteMapIterator(Class<K> k, Class<V> v) throws IOException {
-			this.k = k;
-			this.v = v;
-			long l = readIntAny();
-			if(l < 0 || l > Integer.MAX_VALUE) throw new FormatException();
-			remaining = (int) l;
-		}
-
-		public boolean hasNext() {
-			return remaining > 0;
-		}
-
-		public Entry<K, V> next() {
-			if(remaining == 0) throw new NoSuchElementException();
-			remaining--;
-			try {
-				return new MapEntry<K, V>(readObject(k), readObject(v));
-			} catch(FormatException ex) {
-				throw new FormatRuntimeException();
-			} catch(IOException ex) {
-				throw new RuntimeException(ex);
-			}
-		}
-
-		public void remove() {
-			throw new UnsupportedOperationException();
-		}
-	}
-
-	private class IndefiniteMapIterator<K, V> implements Iterator<Entry<K, V>> {
-
-		private final Class<K> k;
-		private final Class<V> v;
-		private boolean hasNext = true;
-
-		private IndefiniteMapIterator(Class<K> k, Class<V> v)
-		throws IOException {
-			this.k = k;
-			this.v = v;
-			if(hasEnd()) {
-				readEnd();
-				hasNext = false;
-			}
-		}
-
-		public boolean hasNext() {
-			return hasNext;
-		}
-
-		public Entry<K, V> next() {
-			if(!hasNext) throw new NoSuchElementException();
-			try {
-				Entry<K, V> next =
-					new MapEntry<K, V>(readObject(k), readObject(v));
-				if(hasEnd()) {
-					readEnd();
-					hasNext = false;
-				}
-				return next;
-			} catch(FormatException ex) {
-				throw new FormatRuntimeException();
-			} catch(IOException ex) {
-				throw new RuntimeException(ex);
-			}
-		}
-
-		public void remove() {
-			throw new UnsupportedOperationException();
-		}
+	public boolean hasNull() throws IOException {
+		if(!started) readNext(true);
+		if(eof) return false;
+		return next == Tag.NULL;
 	}
 
-	private static class MapEntry<K, V> implements Entry<K, V> {
-
-		private final K k;
-		private final V v;
-
-		MapEntry(K k, V v) {
-			this.k = k;
-			this.v = v;
-		}
-
-		public K getKey() {
-			return k;
-		}
-
-		public V getValue() {
-			return v;
-		}
-
-		public V setValue(V value) {
-			throw new UnsupportedOperationException();
-		}
+	public void readNull() throws IOException {
+		if(!hasNull()) throw new FormatException();
+		readNext(true);
 	}
 }
diff --git a/components/net/sf/briar/serial/WriterImpl.java b/components/net/sf/briar/serial/WriterImpl.java
index 626a47a48f66171e42a2e960220b7657a8a0f612..eb20d6b0294e619b8b433222a06b9629e12fe15f 100644
--- a/components/net/sf/briar/serial/WriterImpl.java
+++ b/components/net/sf/briar/serial/WriterImpl.java
@@ -156,4 +156,9 @@ class WriterImpl implements Writer {
 	public void writeNull() throws IOException {
 		out.write(Tag.NULL);
 	}
+
+	public void close() throws IOException {
+		out.flush();
+		out.close();
+	}
 }
diff --git a/test/net/sf/briar/serial/ReaderImplTest.java b/test/net/sf/briar/serial/ReaderImplTest.java
index f1826f5fd50076b319067a266abc698b2c2bb6a3..a9e7bf5aa88b1d7b61a0f3fecefc7668aab1c1aa 100644
--- a/test/net/sf/briar/serial/ReaderImplTest.java
+++ b/test/net/sf/briar/serial/ReaderImplTest.java
@@ -3,7 +3,6 @@ package net.sf.briar.serial;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -129,21 +128,32 @@ public class ReaderImplTest extends TestCase {
 	}
 
 	@Test
-	public void testReadUtf8MaxLengthNotExceeded() throws IOException {
+	public void testReadUtf8LimitNotExceeded() throws IOException {
 		setContents("F703666F6F");
-		assertEquals("foo", r.readUtf8(3));
+		r.setReadLimit(3);
+		assertEquals("foo", r.readUtf8());
 		assertTrue(r.eof());
 	}
 
 	@Test
-	public void testReadUtf8MaxLengthExceeded() throws IOException {
+	public void testReadUtf8LimitExceeded() throws IOException {
 		setContents("F703666F6F");
+		r.setReadLimit(2);
 		try {
-			r.readUtf8(2);
+			r.readUtf8();
 			assertTrue(false);
 		} catch(FormatException expected) {}
 	}
 
+	@Test
+	public void testReadUtf8LimitReset() throws IOException {
+		setContents("F703666F6F");
+		r.setReadLimit(2);
+		r.resetReadLimit();
+		assertEquals("foo", r.readUtf8());
+		assertTrue(r.eof());
+	}
+
 	@Test
 	public void testReadRaw() throws IOException {
 		setContents("F603010203" + "F603010203" + "F600");
@@ -154,25 +164,36 @@ public class ReaderImplTest extends TestCase {
 	}
 
 	@Test
-	public void testReadRawMaxLengthNotExceeded() throws IOException {
+	public void testReadRawLimitNotExceeded() throws IOException {
 		setContents("F603010203");
-		assertTrue(Arrays.equals(new byte[] {1, 2, 3}, r.readRaw(3)));
+		r.setReadLimit(3);
+		assertTrue(Arrays.equals(new byte[] {1, 2, 3}, r.readRaw()));
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testReadRawMaxLengthExceeded() throws IOException {
 		setContents("F603010203");
+		r.setReadLimit(2);
 		try {
-			r.readRaw(2);
+			r.readRaw();
 			assertTrue(false);
 		} catch(FormatException expected) {}
 	}
 
+	@Test
+	public void testReadRawLimitReset() throws IOException {
+		setContents("F603010203");
+		r.setReadLimit(2);
+		r.resetReadLimit();
+		assertTrue(Arrays.equals(new byte[] {1, 2, 3}, r.readRaw()));
+		assertTrue(r.eof());
+	}
+
 	@Test
 	public void testReadDefiniteList() throws IOException {
 		setContents("F5" + "03" + "01" + "F703666F6F" + "FC0080");
-		List<Object> l = r.readList();
+		List<Object> l = r.readList(Object.class);
 		assertNotNull(l);
 		assertEquals(3, l.size());
 		assertEquals((byte) 1, l.get(0));
@@ -181,21 +202,6 @@ public class ReaderImplTest extends TestCase {
 		assertTrue(r.eof());
 	}
 
-	@Test
-	public void testReadDefiniteListElements() throws IOException {
-		setContents("F5" + "03" + "01" + "F703666F6F" + "FC0080");
-		Iterator<Object> i = r.readListElements();
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		assertEquals((byte) 1, i.next());
-		assertTrue(i.hasNext());
-		assertEquals("foo", i.next());
-		assertTrue(i.hasNext());
-		assertEquals((short) 128, i.next());
-		assertFalse(i.hasNext());
-		assertTrue(r.eof());
-	}
-
 	@Test
 	public void testReadDefiniteListTypeSafe() throws IOException {
 		setContents("F5" + "03" + "01" + "02" + "03");
@@ -208,25 +214,10 @@ public class ReaderImplTest extends TestCase {
 		assertTrue(r.eof());
 	}
 
-	@Test
-	public void testReadDefiniteListElementsTypeSafe() throws IOException {
-		setContents("F5" + "03" + "01" + "02" + "03");
-		Iterator<Byte> i = r.readListElements(Byte.class);
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		assertEquals(Byte.valueOf((byte) 1), i.next());
-		assertTrue(i.hasNext());
-		assertEquals(Byte.valueOf((byte) 2), i.next());
-		assertTrue(i.hasNext());
-		assertEquals(Byte.valueOf((byte) 3), i.next());
-		assertFalse(i.hasNext());
-		assertTrue(r.eof());
-	}
-
 	@Test
 	public void testReadDefiniteMap() throws IOException {
 		setContents("F4" + "02" + "F703666F6F" + "7B" + "F600" + "F0");
-		Map<Object, Object> m = r.readMap();
+		Map<Object, Object> m = r.readMap(Object.class, Object.class);
 		assertNotNull(m);
 		assertEquals(2, m.size());
 		assertEquals((byte) 123, m.get("foo"));
@@ -236,24 +227,6 @@ public class ReaderImplTest extends TestCase {
 		assertTrue(r.eof());
 	}
 
-	@Test
-	public void testReadDefiniteMapEntries() throws IOException {
-		setContents("F4" + "02" + "F703666F6F" + "7B" + "F600" + "F0");
-		Iterator<Entry<Object, Object>> i = r.readMapEntries();
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		Entry<Object, Object> e = i.next();
-		assertNotNull(e);
-		assertEquals("foo", e.getKey());
-		assertEquals((byte) 123, e.getValue());
-		assertTrue(i.hasNext());
-		e = i.next();
-		assertNotNull(e);
-		assertEquals(new RawImpl(new byte[] {}), e.getKey());
-		assertNull(e.getValue());
-		assertTrue(r.eof());
-	}
-
 	@Test
 	public void testReadDefiniteMapTypeSafe() throws IOException {
 		setContents("F4" + "02" + "F703666F6F" + "7B" + "F700" + "F0");
@@ -266,29 +239,10 @@ public class ReaderImplTest extends TestCase {
 		assertTrue(r.eof());
 	}
 
-	@Test
-	public void testReadDefiniteMapEntriesTypeSafe() throws IOException {
-		setContents("F4" + "02" + "F703666F6F" + "7B" + "F700" + "F0");
-		Iterator<Entry<String, Byte>> i =
-			r.readMapEntries(String.class, Byte.class);
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		Entry<String, Byte> e = i.next();
-		assertNotNull(e);
-		assertEquals("foo", e.getKey());
-		assertEquals(Byte.valueOf((byte) 123), e.getValue());
-		assertTrue(i.hasNext());
-		e = i.next();
-		assertNotNull(e);
-		assertEquals("", e.getKey());
-		assertNull(e.getValue());
-		assertTrue(r.eof());
-	}
-
 	@Test
 	public void testReadIndefiniteList() throws IOException {
 		setContents("F3" + "01" + "F703666F6F" + "FC0080" + "F1");
-		List<Object> l = r.readList();
+		List<Object> l = r.readList(Object.class);
 		assertNotNull(l);
 		assertEquals(3, l.size());
 		assertEquals((byte) 1, l.get(0));
@@ -300,15 +254,16 @@ public class ReaderImplTest extends TestCase {
 	@Test
 	public void testReadIndfiniteListElements() throws IOException {
 		setContents("F3" + "01" + "F703666F6F" + "FC0080" + "F1");
-		Iterator<Object> i = r.readListElements();
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		assertEquals((byte) 1, i.next());
-		assertTrue(i.hasNext());
-		assertEquals("foo", i.next());
-		assertTrue(i.hasNext());
-		assertEquals((short) 128, i.next());
-		assertFalse(i.hasNext());
+		assertTrue(r.hasListStart());
+		r.readListStart();
+		assertFalse(r.hasListEnd());
+		assertEquals((byte) 1, r.readIntAny());
+		assertFalse(r.hasListEnd());
+		assertEquals("foo", r.readUtf8());
+		assertFalse(r.hasListEnd());
+		assertEquals((short) 128, r.readIntAny());
+		assertTrue(r.hasListEnd());
+		r.readListEnd();
 		assertTrue(r.eof());
 	}
 
@@ -324,25 +279,10 @@ public class ReaderImplTest extends TestCase {
 		assertTrue(r.eof());
 	}
 
-	@Test
-	public void testReadIndefiniteListElementsTypeSafe() throws IOException {
-		setContents("F3" + "01" + "02" + "03" + "F1");
-		Iterator<Byte> i = r.readListElements(Byte.class);
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		assertEquals(Byte.valueOf((byte) 1), i.next());
-		assertTrue(i.hasNext());
-		assertEquals(Byte.valueOf((byte) 2), i.next());
-		assertTrue(i.hasNext());
-		assertEquals(Byte.valueOf((byte) 3), i.next());
-		assertFalse(i.hasNext());
-		assertTrue(r.eof());
-	}
-
 	@Test
 	public void testReadIndefiniteMap() throws IOException {
 		setContents("F2" + "F703666F6F" + "7B" + "F600" + "F0" + "F1");
-		Map<Object, Object> m = r.readMap();
+		Map<Object, Object> m = r.readMap(Object.class, Object.class);
 		assertNotNull(m);
 		assertEquals(2, m.size());
 		assertEquals((byte) 123, m.get("foo"));
@@ -355,19 +295,19 @@ public class ReaderImplTest extends TestCase {
 	@Test
 	public void testReadIndefiniteMapEntries() throws IOException {
 		setContents("F2" + "F703666F6F" + "7B" + "F600" + "F0" + "F1");
-		Iterator<Entry<Object, Object>> i = r.readMapEntries();
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		Entry<Object, Object> e = i.next();
-		assertNotNull(e);
-		assertEquals("foo", e.getKey());
-		assertEquals((byte) 123, e.getValue());
-		assertTrue(i.hasNext());
-		e = i.next();
-		assertNotNull(e);
-		assertEquals(new RawImpl(new byte[] {}), e.getKey());
-		assertNull(e.getValue());
-		assertFalse(i.hasNext());
+		assertTrue(r.hasMapStart());
+		r.readMapStart();
+		assertFalse(r.hasMapEnd());
+		assertEquals("foo", r.readUtf8());
+		assertFalse(r.hasMapEnd());
+		assertEquals((byte) 123, r.readIntAny());
+		assertFalse(r.hasMapEnd());
+		assertTrue(Arrays.equals(new byte[] {}, r.readRaw()));
+		assertFalse(r.hasMapEnd());
+		assertTrue(r.hasNull());
+		r.readNull();
+		assertTrue(r.hasMapEnd());
+		r.readMapEnd();
 		assertTrue(r.eof());
 	}
 
@@ -383,32 +323,12 @@ public class ReaderImplTest extends TestCase {
 		assertTrue(r.eof());
 	}
 
-	@Test
-	public void testReadIndefiniteMapEntriesTypeSafe() throws IOException {
-		setContents("F2" + "F703666F6F" + "7B" + "F700" + "F0" + "F1");
-		Iterator<Entry<String, Byte>> i =
-			r.readMapEntries(String.class, Byte.class);
-		assertNotNull(i);
-		assertTrue(i.hasNext());
-		Entry<String, Byte> e = i.next();
-		assertNotNull(e);
-		assertEquals("foo", e.getKey());
-		assertEquals(Byte.valueOf((byte) 123), e.getValue());
-		assertTrue(i.hasNext());
-		e = i.next();
-		assertNotNull(e);
-		assertEquals("", e.getKey());
-		assertNull(e.getValue());
-		assertFalse(i.hasNext());
-		assertTrue(r.eof());
-	}
-
 	@Test
 	@SuppressWarnings("unchecked")
 	public void testReadNestedMapsAndLists() throws IOException {
 		setContents("F4" + "01" + "F4" + "01" + "F703666F6F" + "7B" +
 				"F5" + "01" + "01");
-		Map<Object, Object> m = r.readMap();
+		Map<Object, Object> m = r.readMap(Object.class, Object.class);
 		assertNotNull(m);
 		assertEquals(1, m.size());
 		Entry<Object, Object> e = m.entrySet().iterator().next();