diff --git a/briar-api/src/org/briarproject/api/data/BdfDictionary.java b/briar-api/src/org/briarproject/api/data/BdfDictionary.java
index 5fa726fa64b6edf58c248bf7214c458d1400762b..920387cae1fe58775e57367fa4db6e471948b262 100644
--- a/briar-api/src/org/briarproject/api/data/BdfDictionary.java
+++ b/briar-api/src/org/briarproject/api/data/BdfDictionary.java
@@ -40,6 +40,13 @@ public class BdfDictionary extends Hashtable<String, Object> {
 		throw new FormatException();
 	}
 
+	public Boolean getOptionalBoolean(String key) throws FormatException {
+		Object o = get(key);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof Boolean) return (Boolean) o;
+		throw new FormatException();
+	}
+
 	public Boolean getBoolean(String key, Boolean defaultValue) {
 		Object o = get(key);
 		if (o instanceof Boolean) return (Boolean) o;
@@ -55,6 +62,16 @@ public class BdfDictionary extends Hashtable<String, Object> {
 		throw new FormatException();
 	}
 
+	public Long getOptionalLong(String key) throws FormatException {
+		Object o = get(key);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof Long) return (Long) o;
+		if (o instanceof Integer) return ((Integer) o).longValue();
+		if (o instanceof Short) return ((Short) o).longValue();
+		if (o instanceof Byte) return ((Byte) o).longValue();
+		throw new FormatException();
+	}
+
 	public Long getLong(String key, Long defaultValue) {
 		Object o = get(key);
 		if (o instanceof Long) return (Long) o;
@@ -71,6 +88,14 @@ public class BdfDictionary extends Hashtable<String, Object> {
 		throw new FormatException();
 	}
 
+	public Double getOptionalDouble(String key) throws FormatException {
+		Object o = get(key);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof Double) return (Double) o;
+		if (o instanceof Float) return ((Float) o).doubleValue();
+		throw new FormatException();
+	}
+
 	public Double getDouble(String key, Double defaultValue) {
 		Object o = get(key);
 		if (o instanceof Double) return (Double) o;
@@ -84,6 +109,13 @@ public class BdfDictionary extends Hashtable<String, Object> {
 		throw new FormatException();
 	}
 
+	public String getOptionalString(String key) throws FormatException {
+		Object o = get(key);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof String) return (String) o;
+		throw new FormatException();
+	}
+
 	public String getString(String key, String defaultValue) {
 		Object o = get(key);
 		if (o instanceof String) return (String) o;
@@ -97,6 +129,14 @@ public class BdfDictionary extends Hashtable<String, Object> {
 		throw new FormatException();
 	}
 
+	public byte[] getOptionalRaw(String key) throws FormatException {
+		Object o = get(key);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof byte[]) return (byte[]) o;
+		if (o instanceof Bytes) return ((Bytes) o).getBytes();
+		throw new FormatException();
+	}
+
 	public byte[] getRaw(String key, byte[] defaultValue) {
 		Object o = get(key);
 		if (o instanceof byte[]) return (byte[]) o;
@@ -110,6 +150,13 @@ public class BdfDictionary extends Hashtable<String, Object> {
 		throw new FormatException();
 	}
 
+	public BdfList getOptionalList(String key) throws FormatException {
+		Object o = get(key);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof BdfList) return (BdfList) o;
+		throw new FormatException();
+	}
+
 	public BdfList getList(String key, BdfList defaultValue) {
 		Object o = get(key);
 		if (o instanceof BdfList) return (BdfList) o;
@@ -122,6 +169,14 @@ public class BdfDictionary extends Hashtable<String, Object> {
 		throw new FormatException();
 	}
 
+	public BdfDictionary getOptionalDictionary(String key)
+			throws FormatException {
+		Object o = get(key);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof BdfDictionary) return (BdfDictionary) o;
+		throw new FormatException();
+	}
+
 	public BdfDictionary getDictionary(String key, BdfDictionary defaultValue) {
 		Object o = get(key);
 		if (o instanceof BdfDictionary) return (BdfDictionary) o;
diff --git a/briar-api/src/org/briarproject/api/data/BdfList.java b/briar-api/src/org/briarproject/api/data/BdfList.java
index 0cbd0b25292a2b24ff4987066da551524ace2d45..20a68c9477c40888073d0b893a16dea6e598f90e 100644
--- a/briar-api/src/org/briarproject/api/data/BdfList.java
+++ b/briar-api/src/org/briarproject/api/data/BdfList.java
@@ -7,6 +7,8 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Vector;
 
+import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
+
 public class BdfList extends Vector<Object> {
 
 	/**
@@ -33,6 +35,13 @@ public class BdfList extends Vector<Object> {
 		throw new FormatException();
 	}
 
+	public Boolean getOptionalBoolean(int index) throws FormatException {
+		Object o = get(index);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof Boolean) return (Boolean) o;
+		throw new FormatException();
+	}
+
 	public Boolean getBoolean(int index, Boolean defaultValue) {
 		Object o = get(index);
 		if (o instanceof Boolean) return (Boolean) o;
@@ -48,6 +57,16 @@ public class BdfList extends Vector<Object> {
 		throw new FormatException();
 	}
 
+	public Long getOptionalLong(int index) throws FormatException {
+		Object o = get(index);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof Long) return (Long) o;
+		if (o instanceof Integer) return ((Integer) o).longValue();
+		if (o instanceof Short) return ((Short) o).longValue();
+		if (o instanceof Byte) return ((Byte) o).longValue();
+		throw new FormatException();
+	}
+
 	public Long getLong(int index, Long defaultValue) {
 		Object o = get(index);
 		if (o instanceof Long) return (Long) o;
@@ -64,6 +83,14 @@ public class BdfList extends Vector<Object> {
 		throw new FormatException();
 	}
 
+	public Double getOptionalDouble(int index) throws FormatException {
+		Object o = get(index);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof Double) return (Double) o;
+		if (o instanceof Float) return ((Float) o).doubleValue();
+		throw new FormatException();
+	}
+
 	public Double getDouble(int index, Double defaultValue) {
 		Object o = get(index);
 		if (o instanceof Double) return (Double) o;
@@ -77,6 +104,13 @@ public class BdfList extends Vector<Object> {
 		throw new FormatException();
 	}
 
+	public String getOptionalString(int index) throws FormatException {
+		Object o = get(index);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof String) return (String) o;
+		throw new FormatException();
+	}
+
 	public String getString(int index, String defaultValue) {
 		Object o = get(index);
 		if (o instanceof String) return (String) o;
@@ -90,6 +124,14 @@ public class BdfList extends Vector<Object> {
 		throw new FormatException();
 	}
 
+	public byte[] getOptionalRaw(int index) throws FormatException {
+		Object o = get(index);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof byte[]) return (byte[]) o;
+		if (o instanceof Bytes) return ((Bytes) o).getBytes();
+		throw new FormatException();
+	}
+
 	public byte[] getRaw(int index, byte[] defaultValue) {
 		Object o = get(index);
 		if (o instanceof byte[]) return (byte[]) o;
@@ -103,6 +145,13 @@ public class BdfList extends Vector<Object> {
 		throw new FormatException();
 	}
 
+	public BdfList getOptionalList(int index) throws FormatException {
+		Object o = get(index);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof BdfList) return (BdfList) o;
+		throw new FormatException();
+	}
+
 	public BdfList getList(int index, BdfList defaultValue) {
 		Object o = get(index);
 		if (o instanceof BdfList) return (BdfList) o;
@@ -115,6 +164,14 @@ public class BdfList extends Vector<Object> {
 		throw new FormatException();
 	}
 
+	public BdfDictionary getOptionalDictionary(int index)
+			throws FormatException {
+		Object o = get(index);
+		if (o == null || o == NULL_VALUE) return null;
+		if (o instanceof BdfDictionary) return (BdfDictionary) o;
+		throw new FormatException();
+	}
+
 	public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) {
 		Object o = get(index);
 		if (o instanceof BdfDictionary) return (BdfDictionary) o;
diff --git a/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java b/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
index 1de4c8ef62e41cb0c538e0ffcb0c58b08cd0eefb..c35ee3ddb834dd4dd140ee8bde58cabadd8173a4 100644
--- a/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
+++ b/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
@@ -1,186 +1,71 @@
 package org.briarproject.data;
 
+import com.google.inject.Inject;
+
 import org.briarproject.api.Bytes;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.data.BdfWriter;
+import org.briarproject.api.data.BdfWriterFactory;
 import org.briarproject.api.data.MetadataEncoder;
 import org.briarproject.api.db.Metadata;
-import org.briarproject.util.StringUtils;
 
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
 import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
 import static org.briarproject.api.db.Metadata.REMOVE;
-import static org.briarproject.data.Types.DICTIONARY;
-import static org.briarproject.data.Types.END;
-import static org.briarproject.data.Types.FALSE;
-import static org.briarproject.data.Types.FLOAT_64;
-import static org.briarproject.data.Types.INT_16;
-import static org.briarproject.data.Types.INT_32;
-import static org.briarproject.data.Types.INT_64;
-import static org.briarproject.data.Types.INT_8;
-import static org.briarproject.data.Types.LIST;
-import static org.briarproject.data.Types.NULL;
-import static org.briarproject.data.Types.RAW_16;
-import static org.briarproject.data.Types.RAW_32;
-import static org.briarproject.data.Types.RAW_8;
-import static org.briarproject.data.Types.STRING_16;
-import static org.briarproject.data.Types.STRING_32;
-import static org.briarproject.data.Types.STRING_8;
-import static org.briarproject.data.Types.TRUE;
 
 class MetadataEncoderImpl implements MetadataEncoder {
 
+	private final BdfWriterFactory bdfWriterFactory;
+
+	@Inject
+	MetadataEncoderImpl(BdfWriterFactory bdfWriterFactory) {
+		this.bdfWriterFactory = bdfWriterFactory;
+	}
+
 	@Override
 	public Metadata encode(BdfDictionary d) throws FormatException {
 		Metadata m = new Metadata();
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		for (Entry<String, Object> e : d.entrySet()) {
-			if (e.getValue() == NULL_VALUE) {
-				// Special case: if the value is null, the key is being removed
-				m.put(e.getKey(), REMOVE);
-			} else {
-				encodeObject(out, e.getValue());
-				m.put(e.getKey(), out.toByteArray());
-				out.reset();
+		BdfWriter writer = bdfWriterFactory.createWriter(out);
+		try {
+			for (Entry<String, Object> e : d.entrySet()) {
+				if (e.getValue() == NULL_VALUE) {
+					// Special case: if value is null, key is being removed
+					m.put(e.getKey(), REMOVE);
+				} else {
+					encodeObject(writer, e.getValue());
+					m.put(e.getKey(), out.toByteArray());
+					out.reset();
+				}
 			}
+		} catch (FormatException e) {
+			throw e;
+		} catch (IOException e) {
+			throw new RuntimeException(e);
 		}
 		return m;
 	}
 
-	private void encodeObject(ByteArrayOutputStream out, Object o)
-			throws FormatException {
-		if (o == NULL_VALUE) out.write(NULL);
-		else if (o instanceof Boolean) out.write((Boolean) o ? TRUE : FALSE);
-		else if (o instanceof Byte) encodeInteger(out, (Byte) o);
-		else if (o instanceof Short) encodeInteger(out, (Short) o);
-		else if (o instanceof Integer) encodeInteger(out, (Integer) o);
-		else if (o instanceof Long) encodeInteger(out, (Long) o);
-		else if (o instanceof Float) encodeFloat(out, (Float) o);
-		else if (o instanceof Double) encodeFloat(out, (Double) o);
-		else if (o instanceof String) encodeString(out, (String) o);
-		else if (o instanceof byte[]) encodeRaw(out, (byte[]) o);
-		else if (o instanceof Bytes) encodeRaw(out, ((Bytes) o).getBytes());
-		else if (o instanceof List) encodeList(out, (List) o);
-		else if (o instanceof Map) encodeDictionary(out, (Map) o);
+	private void encodeObject(BdfWriter writer, Object o)
+			throws IOException {
+		if (o instanceof Boolean) writer.writeBoolean((Boolean) o);
+		else if (o instanceof Byte) writer.writeLong((Byte) o);
+		else if (o instanceof Short) writer.writeLong((Short) o);
+		else if (o instanceof Integer) writer.writeLong((Integer) o);
+		else if (o instanceof Long) writer.writeLong((Long) o);
+		else if (o instanceof Float) writer.writeDouble((Float) o);
+		else if (o instanceof Double) writer.writeDouble((Double) o);
+		else if (o instanceof String) writer.writeString((String) o);
+		else if (o instanceof byte[]) writer.writeRaw((byte[]) o);
+		else if (o instanceof Bytes) writer.writeRaw(((Bytes) o).getBytes());
+		else if (o instanceof List) writer.writeList((List) o);
+		else if (o instanceof Map) writer.writeDictionary((Map) o);
 		else throw new FormatException();
 	}
-
-	private void encodeInteger(ByteArrayOutputStream out, byte i) {
-		out.write(INT_8);
-		encodeInt8(out, i);
-	}
-
-	private void encodeInteger(ByteArrayOutputStream out, short i) {
-		if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
-			encodeInteger(out, (byte) i);
-		} else {
-			out.write(INT_16);
-			encodeInt16(out, i);
-		}
-	}
-
-	private void encodeInteger(ByteArrayOutputStream out, int i) {
-		if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
-			encodeInteger(out, (short) i);
-		} else {
-			out.write(INT_32);
-			encodeInt32(out, i);
-		}
-	}
-
-	private void encodeInteger(ByteArrayOutputStream out, long i) {
-		if (i >= Integer.MIN_VALUE && i <= Integer.MAX_VALUE) {
-			encodeInteger(out, (int) i);
-		} else {
-			out.write(INT_64);
-			encodeInt64(out, i);
-		}
-	}
-
-	private void encodeInt8(ByteArrayOutputStream out, byte i) {
-		out.write(i);
-	}
-
-	private void encodeInt16(ByteArrayOutputStream out, short i) {
-		out.write((byte) (i >> 8));
-		out.write((byte) ((i << 8) >> 8));
-	}
-
-	private void encodeInt32(ByteArrayOutputStream out, int i) {
-		out.write((byte) (i >> 24));
-		out.write((byte) ((i << 8) >> 24));
-		out.write((byte) ((i << 16) >> 24));
-		out.write((byte) ((i << 24) >> 24));
-	}
-
-	private void encodeInt64(ByteArrayOutputStream out, long i) {
-		out.write((byte) (i >> 56));
-		out.write((byte) ((i << 8) >> 56));
-		out.write((byte) ((i << 16) >> 56));
-		out.write((byte) ((i << 24) >> 56));
-		out.write((byte) ((i << 32) >> 56));
-		out.write((byte) ((i << 40) >> 56));
-		out.write((byte) ((i << 48) >> 56));
-		out.write((byte) ((i << 56) >> 56));
-	}
-
-	private void encodeFloat(ByteArrayOutputStream out, float f) {
-		encodeFloat(out, (double) f);
-	}
-
-	private void encodeFloat(ByteArrayOutputStream out, double d) {
-		out.write(FLOAT_64);
-		encodeInt64(out, Double.doubleToLongBits(d));
-	}
-
-	private void encodeString(ByteArrayOutputStream out, String s) {
-		byte[] b = StringUtils.toUtf8(s);
-		if (b.length <= Byte.MAX_VALUE) {
-			out.write(STRING_8);
-			encodeInt8(out, (byte) b.length);
-		} else if (b.length <= Short.MAX_VALUE) {
-			out.write(STRING_16);
-			encodeInt16(out, (short) b.length);
-		} else {
-			out.write(STRING_32);
-			encodeInt32(out, b.length);
-		}
-		out.write(b, 0, b.length);
-	}
-
-	private void encodeRaw(ByteArrayOutputStream out, byte[] b) {
-		if (b.length <= Byte.MAX_VALUE) {
-			out.write(RAW_8);
-			encodeInt8(out, (byte) b.length);
-		} else if (b.length <= Short.MAX_VALUE) {
-			out.write(RAW_16);
-			encodeInt16(out, (short) b.length);
-		} else {
-			out.write(RAW_32);
-			encodeInt32(out, b.length);
-		}
-		out.write(b, 0, b.length);
-	}
-
-	private void encodeList(ByteArrayOutputStream out, List list)
-			throws FormatException {
-		out.write(LIST);
-		for (Object o : list) encodeObject(out, o);
-		out.write(END);
-	}
-
-	private void encodeDictionary(ByteArrayOutputStream out, Map<?, ?> map)
-			throws FormatException {
-		out.write(DICTIONARY);
-		for (Entry<?, ?> e : map.entrySet()) {
-			if (!(e.getKey() instanceof String)) throw new FormatException();
-			encodeString(out, (String) e.getKey());
-			encodeObject(out, e.getValue());
-		}
-		out.write(END);
-	}
 }
diff --git a/briar-core/src/org/briarproject/data/MetadataParserImpl.java b/briar-core/src/org/briarproject/data/MetadataParserImpl.java
index eadaa34771ac34d624ec9a137cbdfbe31b7a8b9c..7d59970b8c5451b1487c128c085229dc2cdcb11e 100644
--- a/briar-core/src/org/briarproject/data/MetadataParserImpl.java
+++ b/briar-core/src/org/briarproject/data/MetadataParserImpl.java
@@ -1,168 +1,64 @@
 package org.briarproject.data;
 
+import com.google.inject.Inject;
+
 import org.briarproject.api.FormatException;
 import org.briarproject.api.data.BdfDictionary;
-import org.briarproject.api.data.BdfList;
+import org.briarproject.api.data.BdfReader;
+import org.briarproject.api.data.BdfReaderFactory;
 import org.briarproject.api.data.MetadataParser;
 import org.briarproject.api.db.Metadata;
-import org.briarproject.util.StringUtils;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.util.Map.Entry;
 
 import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
 import static org.briarproject.api.db.Metadata.REMOVE;
-import static org.briarproject.data.Types.DICTIONARY;
-import static org.briarproject.data.Types.END;
-import static org.briarproject.data.Types.FALSE;
-import static org.briarproject.data.Types.FLOAT_64;
-import static org.briarproject.data.Types.INT_16;
-import static org.briarproject.data.Types.INT_32;
-import static org.briarproject.data.Types.INT_64;
-import static org.briarproject.data.Types.INT_8;
-import static org.briarproject.data.Types.LIST;
-import static org.briarproject.data.Types.NULL;
-import static org.briarproject.data.Types.RAW_16;
-import static org.briarproject.data.Types.RAW_32;
-import static org.briarproject.data.Types.RAW_8;
-import static org.briarproject.data.Types.STRING_16;
-import static org.briarproject.data.Types.STRING_32;
-import static org.briarproject.data.Types.STRING_8;
-import static org.briarproject.data.Types.TRUE;
 
 class MetadataParserImpl implements MetadataParser {
 
+	private final BdfReaderFactory bdfReaderFactory;
+
+	@Inject
+	MetadataParserImpl(BdfReaderFactory bdfReaderFactory) {
+		this.bdfReaderFactory = bdfReaderFactory;
+	}
+
 	@Override
 	public BdfDictionary parse(Metadata m) throws FormatException {
 		BdfDictionary d = new BdfDictionary();
-		for (Entry<String, byte[]> e : m.entrySet())
-			d.put(e.getKey(), parseValue(e.getValue()));
+		try {
+			for (Entry<String, byte[]> e : m.entrySet()) {
+				// Special case: if key is being removed, value is null
+				if (e.getValue() == REMOVE) d.put(e.getKey(), NULL_VALUE);
+				else d.put(e.getKey(), parseValue(e.getValue()));
+			}
+		} catch (FormatException e) {
+			throw e;
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
 		return d;
 	}
 
-	private Object parseValue(byte[] b) throws FormatException {
-		if (b == REMOVE) return NULL_VALUE;
+	private Object parseValue(byte[] b) throws IOException {
 		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Object o = parseObject(in);
-		if (in.available() > 0) throw new FormatException();
+		BdfReader reader = bdfReaderFactory.createReader(in);
+		Object o = parseObject(reader);
+		if (!reader.eof()) throw new FormatException();
 		return o;
 	}
 
-	private Object parseObject(ByteArrayInputStream in) throws FormatException {
-		switch(in.read()) {
-			case NULL:
-				return NULL_VALUE;
-			case TRUE:
-				return Boolean.TRUE;
-			case FALSE:
-				return Boolean.FALSE;
-			case INT_8:
-				return (long) parseInt8(in);
-			case INT_16:
-				return (long) parseInt16(in);
-			case INT_32:
-				return (long) parseInt32(in);
-			case INT_64:
-				return parseInt64(in);
-			case FLOAT_64:
-				return Double.longBitsToDouble(parseInt64(in));
-			case STRING_8:
-				return parseString(in, parseInt8(in));
-			case STRING_16:
-				return parseString(in, parseInt16(in));
-			case STRING_32:
-				return parseString(in, parseInt32(in));
-			case RAW_8:
-				return parseRaw(in, parseInt8(in));
-			case RAW_16:
-				return parseRaw(in, parseInt16(in));
-			case RAW_32:
-				return parseRaw(in, parseInt32(in));
-			case LIST:
-				return parseList(in);
-			case DICTIONARY:
-				return parseDictionary(in);
-			default:
-				throw new FormatException();
-		}
-	}
-
-	private String parseString(ByteArrayInputStream in) throws FormatException {
-		switch(in.read()) {
-			case STRING_8:
-				return parseString(in, parseInt8(in));
-			case STRING_16:
-				return parseString(in, parseInt16(in));
-			case STRING_32:
-				return parseString(in, parseInt32(in));
-			default:
-				throw new FormatException();
-		}
-	}
-
-	private byte parseInt8(ByteArrayInputStream in) throws FormatException {
-		if (in.available() < 1) throw new FormatException();
-		return (byte) in.read();
-	}
-
-	private short parseInt16(ByteArrayInputStream in) throws FormatException {
-		if (in.available() < 2) throw new FormatException();
-		return (short) (((in.read() & 0xFF) << 8) + (in.read() & 0xFF));
-	}
-
-	private int parseInt32(ByteArrayInputStream in) throws FormatException {
-		if (in.available() < 4) throw new FormatException();
-		int value = 0;
-		for (int i = 0; i < 4; i++)
-			value |= (in.read() & 0xFF) << (24 - i * 8);
-		return value;
-	}
-
-	private long parseInt64(ByteArrayInputStream in) throws FormatException {
-		if (in.available() < 8) throw new FormatException();
-		long value = 0;
-		for (int i = 0; i < 8; i++)
-			value |= (in.read() & 0xFFL) << (56 - i * 8);
-		return value;
-	}
-
-	private String parseString(ByteArrayInputStream in, int len)
-			throws FormatException {
-		if (len < 0) throw new FormatException();
-		byte[] b = new byte[len];
-		if (in.read(b, 0, len) != len) throw new FormatException();
-		return StringUtils.fromUtf8(b, 0, len);
-	}
-
-	private byte[] parseRaw(ByteArrayInputStream in, int len)
-			throws FormatException {
-		if (len < 0) throw new FormatException();
-		byte[] b = new byte[len];
-		if (in.read(b, 0, len) != len) throw new FormatException();
-		return b;
-	}
-
-	private BdfList parseList(ByteArrayInputStream in) throws FormatException {
-		BdfList list = new BdfList();
-		for (int b = peek(in); b != -1 && b != (END & 0xFF); b = peek(in))
-			list.add(parseObject(in));
-		if (in.read() != (END & 0xFF)) throw new FormatException();
-		return list;
-	}
-
-	private BdfDictionary parseDictionary(ByteArrayInputStream in)
-			throws FormatException {
-		BdfDictionary dict = new BdfDictionary();
-		for (int b = peek(in); b != -1 && b != (END & 0xFF); b = peek(in))
-			dict.put(parseString(in), parseObject(in));
-		if (in.read() != (END & 0xFF)) throw new FormatException();
-		return dict;
-	}
-
-	private int peek(ByteArrayInputStream in) {
-		in.mark(1);
-		int next = in.read();
-		in.reset();
-		return next;
+	private Object parseObject(BdfReader reader) throws IOException {
+		if (reader.hasNull()) return NULL_VALUE;
+		if (reader.hasBoolean()) return reader.readBoolean();
+		if (reader.hasLong()) return reader.readLong();
+		if (reader.hasDouble()) return reader.readDouble();
+		if (reader.hasString()) return reader.readString(Integer.MAX_VALUE);
+		if (reader.hasRaw()) return reader.readRaw(Integer.MAX_VALUE);
+		if (reader.hasList()) return reader.readList();
+		if (reader.hasDictionary()) return reader.readDictionary();
+		throw new FormatException();
 	}
 }
diff --git a/briar-tests/src/org/briarproject/data/MetadataEncoderParserImplTest.java b/briar-tests/src/org/briarproject/data/MetadataEncoderParserImplTest.java
index 5ee9ab8cd700ea2446efb3444026187c4551c353..d4dd555d0a6639e558f4a50998ec15bf7d73c60f 100644
--- a/briar-tests/src/org/briarproject/data/MetadataEncoderParserImplTest.java
+++ b/briar-tests/src/org/briarproject/data/MetadataEncoderParserImplTest.java
@@ -4,6 +4,7 @@ import org.briarproject.BriarTestCase;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.db.Metadata;
+import org.junit.Before;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -16,9 +17,16 @@ import static org.junit.Assert.assertEquals;
 
 public class MetadataEncoderParserImplTest extends BriarTestCase {
 
-	MetadataEncoderImpl e = new MetadataEncoderImpl();
-	MetadataParserImpl p = new MetadataParserImpl();
-	BdfDictionary d = new BdfDictionary();
+	MetadataEncoderImpl e;
+	MetadataParserImpl p;
+	BdfDictionary d;
+
+	@Before
+	public void before() {
+		e = new MetadataEncoderImpl(new BdfWriterFactoryImpl());
+		p = new MetadataParserImpl(new BdfReaderFactoryImpl());
+		d = new BdfDictionary();
+	}
 
 	@Test
 	public void testBoolean() throws FormatException {