diff --git a/briar-api/src/org/briarproject/api/data/BdfReader.java b/briar-api/src/org/briarproject/api/data/BdfReader.java
index 813dc86c942fbeed7e347da84e0bef9b01e6dddb..ad0efccf23a43594c2ed306f65afb511dc35a9ec 100644
--- a/briar-api/src/org/briarproject/api/data/BdfReader.java
+++ b/briar-api/src/org/briarproject/api/data/BdfReader.java
@@ -15,13 +15,13 @@ public interface BdfReader {
 	boolean readBoolean() throws IOException;
 	void skipBoolean() throws IOException;
 
-	boolean hasInteger() throws IOException;
-	long readInteger() throws IOException;
-	void skipInteger() throws IOException;
+	boolean hasLong() throws IOException;
+	long readLong() throws IOException;
+	void skipLong() throws IOException;
 
-	boolean hasFloat() throws IOException;
-	double readFloat() throws IOException;
-	void skipFloat() throws IOException;
+	boolean hasDouble() throws IOException;
+	double readDouble() throws IOException;
+	void skipDouble() throws IOException;
 
 	boolean hasString() throws IOException;
 	String readString(int maxLength) throws IOException;
@@ -32,12 +32,14 @@ public interface BdfReader {
 	void skipRaw() throws IOException;
 
 	boolean hasList() throws IOException;
+	BdfList readList() throws IOException;
 	void readListStart() throws IOException;
 	boolean hasListEnd() throws IOException;
 	void readListEnd() throws IOException;
 	void skipList() throws IOException;
 
 	boolean hasDictionary() throws IOException;
+	BdfDictionary readDictionary() throws IOException;
 	void readDictionaryStart() throws IOException;
 	boolean hasDictionaryEnd() throws IOException;
 	void readDictionaryEnd() throws IOException;
diff --git a/briar-core/src/org/briarproject/data/BdfReaderImpl.java b/briar-core/src/org/briarproject/data/BdfReaderImpl.java
index 71917b3bd912bb5fb3ef47578c2a265b32da132f..9c02a26dd0cd6155a20002bf853d473d6b0b8287 100644
--- a/briar-core/src/org/briarproject/data/BdfReaderImpl.java
+++ b/briar-core/src/org/briarproject/data/BdfReaderImpl.java
@@ -1,11 +1,14 @@
 package org.briarproject.data;
 
 import org.briarproject.api.FormatException;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.data.BdfList;
 import org.briarproject.api.data.BdfReader;
 
 import java.io.IOException;
 import java.io.InputStream;
 
+import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
 import static org.briarproject.data.Types.DICTIONARY;
 import static org.briarproject.data.Types.END;
 import static org.briarproject.data.Types.FALSE;
@@ -74,11 +77,26 @@ class BdfReaderImpl implements BdfReader {
 		}
 	}
 
+	private Object readObject() throws IOException {
+		if (hasNull()) {
+			readNull();
+			return NULL_VALUE;
+		}
+		if (hasBoolean()) return readBoolean();
+		if (hasLong()) return readLong();
+		if (hasDouble()) return readDouble();
+		if (hasString()) return readString(Integer.MAX_VALUE);
+		if (hasRaw()) return readRaw(Integer.MAX_VALUE);
+		if (hasList()) return readList();
+		if (hasDictionary()) return readDictionary();
+		throw new FormatException();
+	}
+
 	private void skipObject() throws IOException {
 		if (hasNull()) skipNull();
 		else if (hasBoolean()) skipBoolean();
-		else if (hasInteger()) skipInteger();
-		else if (hasFloat()) skipFloat();
+		else if (hasLong()) skipLong();
+		else if (hasDouble()) skipDouble();
 		else if (hasString()) skipString();
 		else if (hasRaw()) skipRaw();
 		else if (hasList()) skipList();
@@ -129,15 +147,15 @@ class BdfReaderImpl implements BdfReader {
 		hasLookahead = false;
 	}
 
-	public boolean hasInteger() throws IOException {
+	public boolean hasLong() throws IOException {
 		if (!hasLookahead) readLookahead();
 		if (eof) return false;
 		return next == INT_8 || next == INT_16 || next == INT_32 ||
 				next == INT_64;
 	}
 
-	public long readInteger() throws IOException {
-		if (!hasInteger()) throw new FormatException();
+	public long readLong() throws IOException {
+		if (!hasLong()) throw new FormatException();
 		hasLookahead = false;
 		if (next == INT_8) return readInt8();
 		if (next == INT_16) return readInt16();
@@ -169,8 +187,8 @@ class BdfReaderImpl implements BdfReader {
 		return value;
 	}
 
-	public void skipInteger() throws IOException {
-		if (!hasInteger()) throw new FormatException();
+	public void skipLong() throws IOException {
+		if (!hasLong()) throw new FormatException();
 		if (next == INT_8) skip(1);
 		else if (next == INT_16) skip(2);
 		else if (next == INT_32) skip(4);
@@ -178,14 +196,14 @@ class BdfReaderImpl implements BdfReader {
 		hasLookahead = false;
 	}
 
-	public boolean hasFloat() throws IOException {
+	public boolean hasDouble() throws IOException {
 		if (!hasLookahead) readLookahead();
 		if (eof) return false;
 		return next == FLOAT_64;
 	}
 
-	public double readFloat() throws IOException {
-		if (!hasFloat()) throw new FormatException();
+	public double readDouble() throws IOException {
+		if (!hasDouble()) throw new FormatException();
 		hasLookahead = false;
 		readIntoBuffer(8);
 		long value = 0;
@@ -193,8 +211,8 @@ class BdfReaderImpl implements BdfReader {
 		return Double.longBitsToDouble(value);
 	}
 
-	public void skipFloat() throws IOException {
-		if (!hasFloat()) throw new FormatException();
+	public void skipDouble() throws IOException {
+		if (!hasDouble()) throw new FormatException();
 		skip(8);
 		hasLookahead = false;
 	}
@@ -268,6 +286,15 @@ class BdfReaderImpl implements BdfReader {
 		return next == LIST;
 	}
 
+	public BdfList readList() throws IOException {
+		if (!hasList()) throw new FormatException();
+		BdfList list = new BdfList();
+		readListStart();
+		while (!hasListEnd()) list.add(readObject());
+		readListEnd();
+		return list;
+	}
+
 	public void readListStart() throws IOException {
 		if (!hasList()) throw new FormatException();
 		hasLookahead = false;
@@ -305,6 +332,16 @@ class BdfReaderImpl implements BdfReader {
 		return next == DICTIONARY;
 	}
 
+	public BdfDictionary readDictionary() throws IOException {
+		if (!hasDictionary()) throw new FormatException();
+		BdfDictionary dictionary = new BdfDictionary();
+		readDictionaryStart();
+		while (!hasDictionaryEnd())
+			dictionary.put(readString(Integer.MAX_VALUE), readObject());
+		readDictionaryEnd();
+		return dictionary;
+	}
+
 	public void readDictionaryStart() throws IOException {
 		if (!hasDictionary()) throw new FormatException();
 		hasLookahead = false;
diff --git a/briar-core/src/org/briarproject/forum/ForumListValidator.java b/briar-core/src/org/briarproject/forum/ForumListValidator.java
index 98d905c2989f081368cb4ae104460d17f73ebe6d..0a8e04e3226147a03757544112926878a2be37e1 100644
--- a/briar-core/src/org/briarproject/forum/ForumListValidator.java
+++ b/briar-core/src/org/briarproject/forum/ForumListValidator.java
@@ -41,7 +41,7 @@ class ForumListValidator implements MessageValidator {
 					MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
 			BdfReader r = bdfReaderFactory.createReader(in);
 			r.readListStart();
-			long version = r.readInteger();
+			long version = r.readLong();
 			if (version < 0) throw new FormatException();
 			r.readListStart();
 			while (!r.hasListEnd()) {
diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
index 1224a97e1e4b403e233ac73696c853f8e653c783..f371bddc2c5accda1fc46d88bbb8a082abb1bba6 100644
--- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
@@ -345,7 +345,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
 		BdfReader r = bdfReaderFactory.createReader(in);
 		try {
 			r.readListStart();
-			r.skipInteger(); // Version
+			r.skipLong(); // Version
 			r.readListStart();
 			while (!r.hasListEnd()) {
 				r.readListStart();
diff --git a/briar-core/src/org/briarproject/invitation/Connector.java b/briar-core/src/org/briarproject/invitation/Connector.java
index 8b26b16295b672eb22f5b4788a3c7dfaa057e671..a632f9359a482c5fd0f95dc74e4633bdb395c396 100644
--- a/briar-core/src/org/briarproject/invitation/Connector.java
+++ b/briar-core/src/org/briarproject/invitation/Connector.java
@@ -202,7 +202,7 @@ abstract class Connector extends Thread {
 	}
 
 	protected long receiveTimestamp(BdfReader r) throws IOException {
-		long timestamp = r.readInteger();
+		long timestamp = r.readLong();
 		if (timestamp < 0) throw new FormatException();
 		if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received timestamp");
 		return timestamp;
diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
index a254551595f6fa387a6e326a173ada60c3be97bc..70aac05ff6ac3b9fc2caaeb523e3b3801194b56e 100644
--- a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
+++ b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
@@ -342,7 +342,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
 			r.readListStart();
 			r.skipRaw(); // Device ID
 			r.skipString(); // Transport ID
-			r.skipInteger(); // Version
+			r.skipLong(); // Version
 			r.readDictionaryStart();
 			while (!r.hasDictionaryEnd()) {
 				String key = r.readString(MAX_PROPERTY_LENGTH);
diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java b/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java
index a3b7c17832ac5997d3ece03b33418e5ebee9d3c7..06973ae7d8986e7dacd4c50d65b14f66fe7110ff 100644
--- a/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java
+++ b/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java
@@ -57,7 +57,7 @@ class TransportPropertyValidator implements MessageValidator {
 			if (deviceId.length != UniqueId.LENGTH) throw new FormatException();
 			String transportId = r.readString(MAX_TRANSPORT_ID_LENGTH);
 			if (transportId.length() == 0) throw new FormatException();
-			long version = r.readInteger();
+			long version = r.readLong();
 			if (version < 0) throw new FormatException();
 			r.readDictionaryStart();
 			for (int i = 0; !r.hasDictionaryEnd(); i++) {
diff --git a/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java b/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java
index a3309ddac02562881778ae6c2b46af6d4075fa8d..6981b03a06f35ba9ede78074dd24cbadcf5505de 100644
--- a/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java
+++ b/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java
@@ -3,11 +3,14 @@ package org.briarproject.data;
 import org.briarproject.BriarTestCase;
 import org.briarproject.TestUtils;
 import org.briarproject.api.FormatException;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.data.BdfList;
 import org.briarproject.util.StringUtils;
 import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
 
+import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -57,17 +60,17 @@ public class BdfReaderImplTest extends BriarTestCase {
 	public void testReadInt8() throws Exception {
 		setContents("21" + "00" + "21" + "FF"
 				+ "21" + "7F" + "21" + "80");
-		assertEquals(0, r.readInteger());
-		assertEquals(-1, r.readInteger());
-		assertEquals(Byte.MAX_VALUE, r.readInteger());
-		assertEquals(Byte.MIN_VALUE, r.readInteger());
+		assertEquals(0, r.readLong());
+		assertEquals(-1, r.readLong());
+		assertEquals(Byte.MAX_VALUE, r.readLong());
+		assertEquals(Byte.MIN_VALUE, r.readLong());
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testSkipInt8() throws Exception {
 		setContents("21" + "00");
-		r.skipInteger();
+		r.skipLong();
 		assertTrue(r.eof());
 	}
 
@@ -75,17 +78,17 @@ public class BdfReaderImplTest extends BriarTestCase {
 	public void testReadInt16() throws Exception {
 		setContents("22" + "0080" + "22" + "FF7F"
 				+ "22" + "7FFF" + "22" + "8000");
-		assertEquals(Byte.MAX_VALUE + 1, r.readInteger());
-		assertEquals(Byte.MIN_VALUE - 1, r.readInteger());
-		assertEquals(Short.MAX_VALUE, r.readInteger());
-		assertEquals(Short.MIN_VALUE, r.readInteger());
+		assertEquals(Byte.MAX_VALUE + 1, r.readLong());
+		assertEquals(Byte.MIN_VALUE - 1, r.readLong());
+		assertEquals(Short.MAX_VALUE, r.readLong());
+		assertEquals(Short.MIN_VALUE, r.readLong());
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testSkipInt16() throws Exception {
 		setContents("22" + "0080");
-		r.skipInteger();
+		r.skipLong();
 		assertTrue(r.eof());
 	}
 
@@ -93,17 +96,17 @@ public class BdfReaderImplTest extends BriarTestCase {
 	public void testReadInt32() throws Exception {
 		setContents("24" + "00008000" + "24" + "FFFF7FFF"
 				+ "24" + "7FFFFFFF" + "24" + "80000000");
-		assertEquals(Short.MAX_VALUE + 1, r.readInteger());
-		assertEquals(Short.MIN_VALUE - 1, r.readInteger());
-		assertEquals(Integer.MAX_VALUE, r.readInteger());
-		assertEquals(Integer.MIN_VALUE, r.readInteger());
+		assertEquals(Short.MAX_VALUE + 1, r.readLong());
+		assertEquals(Short.MIN_VALUE - 1, r.readLong());
+		assertEquals(Integer.MAX_VALUE, r.readLong());
+		assertEquals(Integer.MIN_VALUE, r.readLong());
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testSkipInt32() throws Exception {
 		setContents("24" + "00008000");
-		r.skipInteger();
+		r.skipLong();
 		assertTrue(r.eof());
 	}
 
@@ -111,17 +114,17 @@ public class BdfReaderImplTest extends BriarTestCase {
 	public void testReadInt64() throws Exception {
 		setContents("28" + "0000000080000000" + "28" + "FFFFFFFF7FFFFFFF"
 				+ "28" + "7FFFFFFFFFFFFFFF" + "28" + "8000000000000000");
-		assertEquals(Integer.MAX_VALUE + 1L, r.readInteger());
-		assertEquals(Integer.MIN_VALUE - 1L, r.readInteger());
-		assertEquals(Long.MAX_VALUE, r.readInteger());
-		assertEquals(Long.MIN_VALUE, r.readInteger());
+		assertEquals(Integer.MAX_VALUE + 1L, r.readLong());
+		assertEquals(Integer.MIN_VALUE - 1L, r.readLong());
+		assertEquals(Long.MAX_VALUE, r.readLong());
+		assertEquals(Long.MIN_VALUE, r.readLong());
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testSkipInt64() throws Exception {
 		setContents("28" + "0000000080000000");
-		r.skipInteger();
+		r.skipLong();
 		assertTrue(r.eof());
 	}
 
@@ -133,21 +136,23 @@ public class BdfReaderImplTest extends BriarTestCase {
 				+ "38" + "4000000000000000" + "38" + "BFF0000000000000"
 				+ "38" + "8000000000000000" + "38" + "FFF0000000000000"
 				+ "38" + "7FF0000000000000" + "38" + "7FF8000000000000");
-		assertEquals(0, Double.compare(0.0, r.readFloat()));
-		assertEquals(0, Double.compare(1.0, r.readFloat()));
-		assertEquals(0, Double.compare(2.0, r.readFloat()));
-		assertEquals(0, Double.compare(-1.0, r.readFloat()));
-		assertEquals(0, Double.compare(-0.0, r.readFloat()));
-		assertEquals(0, Double.compare(Double.NEGATIVE_INFINITY, r.readFloat()));
-		assertEquals(0, Double.compare(Double.POSITIVE_INFINITY, r.readFloat()));
-		assertTrue(Double.isNaN(r.readFloat()));
+		assertEquals(0, Double.compare(0.0, r.readDouble()));
+		assertEquals(0, Double.compare(1.0, r.readDouble()));
+		assertEquals(0, Double.compare(2.0, r.readDouble()));
+		assertEquals(0, Double.compare(-1.0, r.readDouble()));
+		assertEquals(0, Double.compare(-0.0, r.readDouble()));
+		assertEquals(0, Double.compare(Double.NEGATIVE_INFINITY,
+				r.readDouble()));
+		assertEquals(0, Double.compare(Double.POSITIVE_INFINITY,
+				r.readDouble()));
+		assertTrue(Double.isNaN(r.readDouble()));
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testSkipFloat() throws Exception {
 		setContents("38" + "0000000000000000");
-		r.skipFloat();
+		r.skipDouble();
 		assertTrue(r.eof());
 	}
 
@@ -377,17 +382,31 @@ public class BdfReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testReadList() throws Exception {
-		// A list containing 1, "foo", and 128
+		// A list containing 1, "foo", and null
 		setContents("60" + "21" + "01" +
 				"41" + "03" + "666F6F" +
-				"22" + "0080" + "80");
+				"00" + "80");
+		BdfList list = r.readList();
+		assertEquals(3, list.size());
+		assertEquals(1L, list.get(0));
+		assertEquals("foo", list.get(1));
+		assertEquals(NULL_VALUE, list.get(2));
+	}
+
+	@Test
+	public void testReadListManually() throws Exception {
+		// A list containing 1, "foo", and null
+		setContents("60" + "21" + "01" +
+				"41" + "03" + "666F6F" +
+				"00" + "80");
 		r.readListStart();
 		assertFalse(r.hasListEnd());
-		assertEquals(1, r.readInteger());
+		assertEquals(1, r.readLong());
 		assertFalse(r.hasListEnd());
 		assertEquals("foo", r.readString(1000));
 		assertFalse(r.hasListEnd());
-		assertEquals(128, r.readInteger());
+		assertTrue(r.hasNull());
+		r.readNull();
 		assertTrue(r.hasListEnd());
 		r.readListEnd();
 		assertTrue(r.eof());
@@ -405,6 +424,19 @@ public class BdfReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testReadDictionary() throws Exception {
+		// A dictionary containing "foo" -> 123 and "bar" -> null
+		setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
+				"41" + "03" + "626172" + "00" + "80");
+		BdfDictionary dictionary = r.readDictionary();
+		assertEquals(2, dictionary.size());
+		assertTrue(dictionary.containsKey("foo"));
+		assertEquals(123L, dictionary.get("foo"));
+		assertTrue(dictionary.containsKey("bar"));
+		assertEquals(NULL_VALUE, dictionary.get("bar"));
+	}
+
+	@Test
+	public void testReadDictionaryManually() throws Exception {
 		// A dictionary containing "foo" -> 123 and "bar" -> null
 		setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
 				"41" + "03" + "626172" + "00" + "80");
@@ -412,7 +444,7 @@ public class BdfReaderImplTest extends BriarTestCase {
 		assertFalse(r.hasDictionaryEnd());
 		assertEquals("foo", r.readString(1000));
 		assertFalse(r.hasDictionaryEnd());
-		assertEquals(123, r.readInteger());
+		assertEquals(123, r.readLong());
 		assertFalse(r.hasDictionaryEnd());
 		assertEquals("bar", r.readString(1000));
 		assertFalse(r.hasDictionaryEnd());