diff --git a/briar-android/src/org/briarproject/android/contact/SelectContactsDialog.java b/briar-android/src/org/briarproject/android/contact/SelectContactsDialog.java
index 0fb4b929225d920cf2b53cbf03d881f72188bc22..68350324dfd8c5dbad160953dafea7d16b4b3152 100644
--- a/briar-android/src/org/briarproject/android/contact/SelectContactsDialog.java
+++ b/briar-android/src/org/briarproject/android/contact/SelectContactsDialog.java
@@ -31,6 +31,7 @@ implements DialogInterface.OnMultiChoiceClickListener {
 
 	@Override
 	public Dialog onCreateDialog(Bundle state) {
+		if(listener == null || contacts == null) return null;
 		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 		String[] names = new String[contacts.length];
 		for(int i = 0; i < contacts.length; i++)
diff --git a/briar-api/src/org/briarproject/api/serial/Reader.java b/briar-api/src/org/briarproject/api/serial/Reader.java
index f1591f354883e342c16b6e7b5f56bc46db6da7c5..59113c414c9bea2659a7257216191f611f9188cf 100644
--- a/briar-api/src/org/briarproject/api/serial/Reader.java
+++ b/briar-api/src/org/briarproject/api/serial/Reader.java
@@ -14,37 +14,13 @@ public interface Reader {
 	boolean readBoolean() throws IOException;
 	void skipBoolean() throws IOException;
 
-	boolean hasUint7() throws IOException;
-	byte readUint7() throws IOException;
-	void skipUint7() throws IOException;
+	boolean hasInteger() throws IOException;
+	long readInteger() throws IOException;
+	void skipInteger() throws IOException;
 
-	boolean hasInt8() throws IOException;
-	byte readInt8() throws IOException;
-	void skipInt8() throws IOException;
-
-	boolean hasInt16() throws IOException;
-	short readInt16() throws IOException;
-	void skipInt16() throws IOException;
-
-	boolean hasInt32() throws IOException;
-	int readInt32() throws IOException;
-	void skipInt32() throws IOException;
-
-	boolean hasInt64() throws IOException;
-	long readInt64() throws IOException;
-	void skipInt64() throws IOException;
-
-	boolean hasIntAny() throws IOException;
-	long readIntAny() throws IOException;
-	void skipIntAny() throws IOException;
-
-	boolean hasFloat32() throws IOException;
-	float readFloat32() throws IOException;
-	void skipFloat32() throws IOException;
-
-	boolean hasFloat64() throws IOException;
-	double readFloat64() throws IOException;
-	void skipFloat64() throws IOException;
+	boolean hasFloat() throws IOException;
+	double readFloat() throws IOException;
+	void skipFloat() throws IOException;
 
 	boolean hasString() throws IOException;
 	String readString(int maxLength) throws IOException;
diff --git a/briar-api/src/org/briarproject/api/serial/Writer.java b/briar-api/src/org/briarproject/api/serial/Writer.java
index ea972e14059f291739c73aee0d8c81b8c4d0538a..2ad638bbc83382b7a50f2792a4c57822d31ee3b1 100644
--- a/briar-api/src/org/briarproject/api/serial/Writer.java
+++ b/briar-api/src/org/briarproject/api/serial/Writer.java
@@ -13,17 +13,8 @@ public interface Writer {
 	void removeConsumer(Consumer c);
 
 	void writeBoolean(boolean b) throws IOException;
-
-	void writeUint7(byte b) throws IOException;
-	void writeInt8(byte b) throws IOException;
-	void writeInt16(short s) throws IOException;
-	void writeInt32(int i) throws IOException;
-	void writeInt64(long l) throws IOException;
-	void writeIntAny(long l) throws IOException;
-
-	void writeFloat32(float f) throws IOException;
-	void writeFloat64(double d) throws IOException;
-
+	void writeInteger(long l) throws IOException;
+	void writeFloat(double d) throws IOException;
 	void writeString(String s) throws IOException;
 	void writeBytes(byte[] b) throws IOException;
 
diff --git a/briar-core/src/org/briarproject/invitation/Connector.java b/briar-core/src/org/briarproject/invitation/Connector.java
index b19edf2c7dc67235cbc138e3fdff9e7a427b8775..426c036a7e1f8e8249e3695a011dd9bf6ab71be3 100644
--- a/briar-core/src/org/briarproject/invitation/Connector.java
+++ b/briar-core/src/org/briarproject/invitation/Connector.java
@@ -218,13 +218,13 @@ abstract class Connector extends Thread {
 	}
 
 	protected void sendTimestamp(Writer w, long timestamp) throws IOException {
-		w.writeInt64(timestamp);
+		w.writeInteger(timestamp);
 		w.flush();
 		if(LOG.isLoggable(INFO)) LOG.info(pluginName + " sent timestamp");
 	}
 
 	protected long receiveTimestamp(Reader r) throws IOException {
-		long timestamp = r.readInt64();
+		long timestamp = r.readInteger();
 		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/messaging/MessageFactoryImpl.java b/briar-core/src/org/briarproject/messaging/MessageFactoryImpl.java
index 9a05e6c27769dcf8c00e99e802f4b19de8ea5d4d..f32905e5333db5506849af3128df24418f11b565 100644
--- a/briar-core/src/org/briarproject/messaging/MessageFactoryImpl.java
+++ b/briar-core/src/org/briarproject/messaging/MessageFactoryImpl.java
@@ -94,7 +94,7 @@ class MessageFactoryImpl implements MessageFactory {
 		if(author == null) w.writeNull();
 		else writeAuthor(w, author);
 		w.writeString(contentType);
-		w.writeIntAny(timestamp);
+		w.writeInteger(timestamp);
 		byte[] salt = new byte[MESSAGE_SALT_LENGTH];
 		random.nextBytes(salt);
 		w.writeBytes(salt);
diff --git a/briar-core/src/org/briarproject/messaging/MessageReader.java b/briar-core/src/org/briarproject/messaging/MessageReader.java
index f089e4b87c851601b3c58ce9bdea30540170313b..198c34a750e00570f75a22737bf146a15e7f5336 100644
--- a/briar-core/src/org/briarproject/messaging/MessageReader.java
+++ b/briar-core/src/org/briarproject/messaging/MessageReader.java
@@ -56,7 +56,7 @@ class MessageReader implements StructReader<UnverifiedMessage> {
 		// Read the content type
 		String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH);
 		// Read the timestamp
-		long timestamp = r.readIntAny();
+		long timestamp = r.readInteger();
 		if(timestamp < 0) throw new FormatException();
 		// Read the salt
 		byte[] salt = r.readBytes(MESSAGE_SALT_LENGTH);
diff --git a/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java b/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java
index 6e65ee61f9bd00ca74ffeb7bc231d637a241c414..7adcc723cdc1534aaa1e0bf8b0ea46b94e183316 100644
--- a/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java
+++ b/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java
@@ -165,7 +165,7 @@ class PacketReaderImpl implements PacketReader {
 
 	public RetentionAck readRetentionAck() throws IOException {
 		r.readStructStart(RETENTION_ACK);
-		long version = r.readIntAny();
+		long version = r.readInteger();
 		if(version < 0) throw new FormatException();
 		r.readStructEnd();
 		return new RetentionAck(version);
@@ -177,9 +177,9 @@ class PacketReaderImpl implements PacketReader {
 
 	public RetentionUpdate readRetentionUpdate() throws IOException {
 		r.readStructStart(RETENTION_UPDATE);
-		long retention = r.readIntAny();
+		long retention = r.readInteger();
 		if(retention < 0) throw new FormatException();
-		long version = r.readIntAny();
+		long version = r.readInteger();
 		if(version < 0) throw new FormatException();
 		r.readStructEnd();
 		return new RetentionUpdate(retention, version);
@@ -191,7 +191,7 @@ class PacketReaderImpl implements PacketReader {
 
 	public SubscriptionAck readSubscriptionAck() throws IOException {
 		r.readStructStart(SUBSCRIPTION_ACK);
-		long version = r.readIntAny();
+		long version = r.readInteger();
 		if(version < 0) throw new FormatException();
 		r.readStructEnd();
 		return new SubscriptionAck(version);
@@ -213,7 +213,7 @@ class PacketReaderImpl implements PacketReader {
 		r.readStructStart(TRANSPORT_ACK);
 		byte[] b = r.readBytes(UniqueId.LENGTH);
 		if(b.length < UniqueId.LENGTH) throw new FormatException();
-		long version = r.readIntAny();
+		long version = r.readInteger();
 		if(version < 0) throw new FormatException();
 		r.readStructEnd();
 		return new TransportAck(new TransportId(b), version);
@@ -245,7 +245,7 @@ class PacketReaderImpl implements PacketReader {
 		}
 		r.readMapEnd();
 		// Read the version number
-		long version = r.readIntAny();
+		long version = r.readInteger();
 		if(version < 0) throw new FormatException();
 		// Read the end of the struct
 		r.readStructEnd();
diff --git a/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java b/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java
index fafbdb01e8a798866429a4c398bed0dd554007af..671cc3d7e9848a720f2818a38ad801bf659136c7 100644
--- a/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java
+++ b/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java
@@ -101,22 +101,22 @@ class PacketWriterImpl implements PacketWriter {
 
 	public void writeRetentionAck(RetentionAck a) throws IOException {
 		w.writeStructStart(RETENTION_ACK);
-		w.writeIntAny(a.getVersion());
+		w.writeInteger(a.getVersion());
 		w.writeStructEnd();
 		if(flush) out.flush();
 	}
 
 	public void writeRetentionUpdate(RetentionUpdate u) throws IOException {
 		w.writeStructStart(RETENTION_UPDATE);
-		w.writeIntAny(u.getRetentionTime());
-		w.writeIntAny(u.getVersion());
+		w.writeInteger(u.getRetentionTime());
+		w.writeInteger(u.getVersion());
 		w.writeStructEnd();
 		if(flush) out.flush();
 	}
 
 	public void writeSubscriptionAck(SubscriptionAck a) throws IOException {
 		w.writeStructStart(SUBSCRIPTION_ACK);
-		w.writeIntAny(a.getVersion());
+		w.writeInteger(a.getVersion());
 		w.writeStructEnd();
 		if(flush) out.flush();
 	}
@@ -132,7 +132,7 @@ class PacketWriterImpl implements PacketWriter {
 			w.writeStructEnd();
 		}
 		w.writeListEnd();
-		w.writeIntAny(u.getVersion());
+		w.writeInteger(u.getVersion());
 		w.writeStructEnd();
 		if(flush) out.flush();
 	}
@@ -140,7 +140,7 @@ class PacketWriterImpl implements PacketWriter {
 	public void writeTransportAck(TransportAck a) throws IOException {
 		w.writeStructStart(TRANSPORT_ACK);
 		w.writeBytes(a.getId().getBytes());
-		w.writeIntAny(a.getVersion());
+		w.writeInteger(a.getVersion());
 		w.writeStructEnd();
 		if(flush) out.flush();
 	}
@@ -149,7 +149,7 @@ class PacketWriterImpl implements PacketWriter {
 		w.writeStructStart(TRANSPORT_UPDATE);
 		w.writeBytes(u.getId().getBytes());
 		w.writeMap(u.getProperties());
-		w.writeIntAny(u.getVersion());
+		w.writeInteger(u.getVersion());
 		w.writeStructEnd();
 		if(flush) out.flush();
 	}
diff --git a/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java b/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java
index f255b90eee1310d6c3c7688cb9823b53b789a329..f9db08a2668ae8f8a851c6f2959f3cab1ce73e00 100644
--- a/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java
+++ b/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java
@@ -38,7 +38,7 @@ class SubscriptionUpdateReader implements StructReader<SubscriptionUpdate> {
 			groups.add(groupReader.readStruct(r));
 		r.readListEnd();
 		// Read the version number
-		long version = r.readIntAny();
+		long version = r.readInteger();
 		if(version < 0) throw new FormatException();
 		// Read the end of the struct
 		r.readStructEnd();
diff --git a/briar-core/src/org/briarproject/serial/ReaderImpl.java b/briar-core/src/org/briarproject/serial/ReaderImpl.java
index 344d2380fe91c0a5b81d8282344105a07a623712..6a644bff6e187b2d66d791b1b4865ba3f942df6b 100644
--- a/briar-core/src/org/briarproject/serial/ReaderImpl.java
+++ b/briar-core/src/org/briarproject/serial/ReaderImpl.java
@@ -1,5 +1,17 @@
 package org.briarproject.serial;
 
+import static org.briarproject.serial.Tag.BYTES;
+import static org.briarproject.serial.Tag.END;
+import static org.briarproject.serial.Tag.FALSE;
+import static org.briarproject.serial.Tag.FLOAT;
+import static org.briarproject.serial.Tag.INTEGER;
+import static org.briarproject.serial.Tag.LIST;
+import static org.briarproject.serial.Tag.MAP;
+import static org.briarproject.serial.Tag.NULL;
+import static org.briarproject.serial.Tag.STRING;
+import static org.briarproject.serial.Tag.STRUCT;
+import static org.briarproject.serial.Tag.TRUE;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -25,15 +37,9 @@ class ReaderImpl implements Reader {
 		this.in = in;
 	}
 
-	public boolean eof() throws IOException {
-		if(!hasLookahead) readLookahead();
-		return eof;
-	}
-
 	private void readLookahead() throws IOException {
 		assert !eof;
-		// If one or two lookahead bytes have been read, feed the consumers
-		if(hasLookahead) consumeLookahead();
+		assert !hasLookahead;
 		// Read a lookahead byte
 		int i = in.read();
 		if(i == -1) {
@@ -42,7 +48,7 @@ class ReaderImpl implements Reader {
 		}
 		next = (byte) i;
 		// If necessary, read another lookahead byte
-		if(next == Tag.STRUCT) {
+		if(next == STRUCT) {
 			i = in.read();
 			if(i == -1) throw new FormatException();
 			nextStructId = (byte) i;
@@ -54,323 +60,186 @@ class ReaderImpl implements Reader {
 		assert hasLookahead;
 		for(Consumer c : consumers) {
 			c.write(next);
-			if(next == Tag.STRUCT) c.write(nextStructId);
+			if(next == STRUCT) c.write(nextStructId);
 		}
 		hasLookahead = false;
 	}
 
-	public void close() throws IOException {
-		in.close();
-	}
-
-	public void addConsumer(Consumer c) {
-		consumers.add(c);
-	}
-
-	public void removeConsumer(Consumer c) {
-		if(!consumers.remove(c)) throw new IllegalArgumentException();
-	}
-
-	public boolean hasBoolean() throws IOException {
-		if(!hasLookahead) readLookahead();
-		if(eof) return false;
-		return next == Tag.FALSE || next == Tag.TRUE;
-	}
-
-	public boolean readBoolean() throws IOException {
-		if(!hasBoolean()) throw new FormatException();
-		consumeLookahead();
-		return next == Tag.TRUE;
-	}
-
-	public void skipBoolean() throws IOException {
-		if(!hasBoolean()) throw new FormatException();
-		hasLookahead = false;
-	}
-
-	public boolean hasUint7() throws IOException {
-		if(!hasLookahead) readLookahead();
-		if(eof) return false;
-		return next >= 0;
-	}
-
-	public byte readUint7() throws IOException {
-		if(!hasUint7()) throw new FormatException();
-		consumeLookahead();
-		return next;
-	}
-
-	public void skipUint7() throws IOException {
-		if(!hasUint7()) throw new FormatException();
-		hasLookahead = false;
-	}
-
-	public boolean hasInt8() throws IOException {
-		if(!hasLookahead) readLookahead();
-		if(eof) return false;
-		return next == Tag.INT8;
-	}
-
-	public byte readInt8() throws IOException {
-		if(!hasInt8()) throw new FormatException();
-		consumeLookahead();
-		int i = in.read();
-		if(i == -1) {
-			eof = true;
-			throw new FormatException();
-		}
-		byte b = (byte) i;
-		// Feed the hungry mouths
-		for(Consumer c : consumers) c.write(b);
-		return b;
-	}
-
-	public void skipInt8() throws IOException {
-		if(!hasInt8()) throw new FormatException();
-		if(in.read() == -1) {
-			eof = true;
-			throw new FormatException();
+	private void readIntoBuffer(byte[] b, int length, boolean consume)
+			throws IOException {
+		int offset = 0;
+		while(offset < length) {
+			int read = in.read(b, offset, length - offset);
+			if(read == -1) throw new FormatException();
+			offset += read;
 		}
-		hasLookahead = false;
+		if(consume) for(Consumer c : consumers) c.write(b, 0, length);
 	}
 
-	public boolean hasInt16() throws IOException {
-		if(!hasLookahead) readLookahead();
-		if(eof) return false;
-		return next == Tag.INT16;
-	}
-
-	public short readInt16() throws IOException {
-		if(!hasInt16()) throw new FormatException();
-		consumeLookahead();
-		readIntoBuffer(2);
-		return (short) (((buf[0] & 0xFF) << 8) | (buf[1] & 0xFF));
-	}
-
-	private void readIntoBuffer(int length) throws IOException {
+	private void readIntoBuffer(int length, boolean consume)
+			throws IOException {
 		if(buf.length < length) buf = new byte[length];
-		readIntoBuffer(buf, length);
+		readIntoBuffer(buf, length, consume);
 	}
 
-	private void readIntoBuffer(byte[] b, int length) throws IOException {
-		assert !hasLookahead;
-		int offset = 0;
-		while(offset < length) {
-			int read = in.read(b, offset, length - offset);
-			if(read == -1) {
-				eof = true;
-				throw new FormatException();
-			}
-			offset += read;
-		}
-		// Feed the hungry mouths
-		for(Consumer c : consumers) c.write(b, 0, length);
+	private int readInt32(boolean consume) throws IOException {
+		readIntoBuffer(4, consume);
+		int value = 0;
+		for(int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
+		return value;
 	}
 
-	public void skipInt16() throws IOException {
-		if(!hasInt16()) throw new FormatException();
-		hasLookahead = false;
-		skip(2);
+	private long readInt64(boolean consume) throws IOException {
+		readIntoBuffer(8, consume);
+		long value = 0;
+		for(int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
+		return value;
 	}
 
 	private void skip(int length) throws IOException {
 		while(length > 0) {
 			int read = in.read(buf, 0, Math.min(length, buf.length));
-			if(read == -1) {
-				eof = true;
-				throw new FormatException();
-			}
+			if(read == -1) throw new FormatException();
 			length -= read;
 		}
 	}
 
-	public boolean hasInt32() throws IOException {
-		if(!hasLookahead) readLookahead();
-		if(eof) return false;
-		return next == Tag.INT32;
-	}
-
-	public int readInt32() throws IOException {
-		if(!hasInt32()) throw new FormatException();
-		consumeLookahead();
-		return readInt32Bits();
-	}
-
-	private int readInt32Bits() throws IOException {
-		readIntoBuffer(4);
-		return ((buf[0] & 0xFF) << 24) | ((buf[1] & 0xFF) << 16) |
-				((buf[2] & 0xFF) << 8) | (buf[3] & 0xFF);
-	}
-
-	public void skipInt32() throws IOException {
-		if(!hasInt32()) throw new FormatException();
-		hasLookahead = false;
-		skip(4);
+	private void skipObject() throws IOException {
+		if(hasBoolean()) skipBoolean();
+		else if(hasInteger()) skipInteger();
+		else if(hasFloat()) skipFloat();
+		else if(hasString()) skipString(Integer.MAX_VALUE);
+		else if(hasBytes()) skipBytes(Integer.MAX_VALUE);
+		else if(hasList()) skipList();
+		else if(hasMap()) skipMap();
+		else if(hasStruct()) skipStruct();
+		else if(hasNull()) skipNull();
+		else throw new FormatException();
 	}
 
-	public boolean hasInt64() throws IOException {
+	public boolean eof() throws IOException {
 		if(!hasLookahead) readLookahead();
-		if(eof) return false;
-		return next == Tag.INT64;
+		return eof;
 	}
 
-	public long readInt64() throws IOException {
-		if(!hasInt64()) throw new FormatException();
-		consumeLookahead();
-		return readInt64Bits();
+	public void close() throws IOException {
+		in.close();
 	}
 
-	private long readInt64Bits() throws IOException {
-		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 void addConsumer(Consumer c) {
+		consumers.add(c);
 	}
 
-	public void skipInt64() throws IOException {
-		if(!hasInt64()) throw new FormatException();
-		hasLookahead = false;
-		skip(8);
+	public void removeConsumer(Consumer c) {
+		if(!consumers.remove(c)) throw new IllegalArgumentException();
 	}
 
-	public boolean hasIntAny() throws IOException {
+	public boolean hasBoolean() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next >= 0 || next == Tag.INT8 || next == Tag.INT16
-				|| next == Tag.INT32 || next == Tag.INT64;
+		return next == FALSE || next == TRUE;
 	}
 
-	public long readIntAny() throws IOException {
-		if(!hasIntAny()) throw new FormatException();
-		if(next >= 0) return readUint7();
-		if(next == Tag.INT8) return readInt8();
-		if(next == Tag.INT16) return readInt16();
-		if(next == Tag.INT32) return readInt32();
-		if(next == Tag.INT64) return readInt64();
-		throw new IllegalStateException();
+	public boolean readBoolean() throws IOException {
+		if(!hasBoolean()) throw new FormatException();
+		consumeLookahead();
+		return next == TRUE;
 	}
 
-	public void skipIntAny() throws IOException {
-		if(!hasIntAny()) throw new FormatException();
-		if(next >= 0) skipUint7();
-		else if(next == Tag.INT8) skipInt8();
-		else if(next == Tag.INT16) skipInt16();
-		else if(next == Tag.INT32) skipInt32();
-		else if(next == Tag.INT64) skipInt64();
-		else throw new IllegalStateException();
+	public void skipBoolean() throws IOException {
+		if(!hasBoolean()) throw new FormatException();
+		hasLookahead = false;
 	}
 
-	public boolean hasFloat32() throws IOException {
+	public boolean hasInteger() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.FLOAT32;
+		return next == INTEGER;
 	}
 
-	public float readFloat32() throws IOException {
-		if(!hasFloat32()) throw new FormatException();
+	public long readInteger() throws IOException {
+		if(!hasInteger()) throw new FormatException();
 		consumeLookahead();
-		return Float.intBitsToFloat(readInt32Bits());
+		return readInt64(true);
 	}
 
-	public void skipFloat32() throws IOException {
-		if(!hasFloat32()) throw new FormatException();
+	public void skipInteger() throws IOException {
+		if(!hasInteger()) throw new FormatException();
+		skip(8);
 		hasLookahead = false;
-		skip(4);
 	}
 
-	public boolean hasFloat64() throws IOException {
+	public boolean hasFloat() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.FLOAT64;
+		return next == FLOAT;
 	}
 
-	public double readFloat64() throws IOException {
-		if(!hasFloat64()) throw new FormatException();
+	public double readFloat() throws IOException {
+		if(!hasFloat()) throw new FormatException();
 		consumeLookahead();
-		return Double.longBitsToDouble(readInt64Bits());
+		return Double.longBitsToDouble(readInt64(true));
 	}
 
-	public void skipFloat64() throws IOException {
-		if(!hasFloat64()) throw new FormatException();
-		hasLookahead = false;
+	public void skipFloat() throws IOException {
+		if(!hasFloat()) throw new FormatException();
 		skip(8);
+		hasLookahead = false;
 	}
 
 	public boolean hasString() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.STRING;
+		return next == STRING;
 	}
 
 	public String readString(int maxLength) throws IOException {
 		if(!hasString()) throw new FormatException();
 		consumeLookahead();
-		int length = readLength();
-		if(length > maxLength) throw new FormatException();
+		int length = readInt32(true);
+		if(length < 0 || length > maxLength) throw new FormatException();
 		if(length == 0) return "";
-		readIntoBuffer(length);
+		readIntoBuffer(length, true);
 		return new String(buf, 0, length, "UTF-8");
 	}
 
-	private int readLength() throws IOException {
-		if(!hasLength()) throw new FormatException();
-		int length;
-		if(next >= 0) length = readUint7();
-		else if(next == Tag.INT8) length = readInt8();
-		else if(next == Tag.INT16) length = readInt16();
-		else if(next == Tag.INT32) length = readInt32();
-		else throw new IllegalStateException();
-		if(length < 0) throw new FormatException();
-		return length;
-	}
-
-	private boolean hasLength() throws IOException {
-		if(!hasLookahead) readLookahead();
-		if(eof) return false;
-		return next >= 0 || next == Tag.INT8 || next == Tag.INT16
-				|| next == Tag.INT32;
-	}
-
 	public void skipString(int maxLength) throws IOException {
 		if(!hasString()) throw new FormatException();
-		hasLookahead = false;
-		int length = readLength();
-		if(length > maxLength) throw new FormatException();
-		hasLookahead = false;
+		int length = readInt32(false);
+		if(length < 0 || length > maxLength) throw new FormatException();
 		skip(length);
+		hasLookahead = false;
 	}
 
 	public boolean hasBytes() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.BYTES;
+		return next == BYTES;
 	}
 
 	public byte[] readBytes(int maxLength) throws IOException {
 		if(!hasBytes()) throw new FormatException();
 		consumeLookahead();
-		int length = readLength();
-		if(length > maxLength) throw new FormatException();
+		int length = readInt32(true);
+		if(length < 0 || length > maxLength) throw new FormatException();
 		if(length == 0) return EMPTY_BUFFER;
 		byte[] b = new byte[length];
-		readIntoBuffer(b, length);
+		readIntoBuffer(b, length, true);
 		return b;
 	}
 
 	public void skipBytes(int maxLength) throws IOException {
 		if(!hasBytes()) throw new FormatException();
-		hasLookahead = false;
-		int length = readLength();
-		if(length > maxLength) throw new FormatException();
-		hasLookahead = false;
+		int length = readInt32(false);
+		if(length < 0 || length > maxLength) throw new FormatException();
 		skip(length);
+		hasLookahead = false;
 	}
 
 	public boolean hasList() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.LIST;
+		return next == LIST;
 	}
 
 	public void readListStart() throws IOException {
@@ -385,7 +254,7 @@ class ReaderImpl implements Reader {
 	private boolean hasEnd() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.END;
+		return next == END;
 	}
 
 	public void readListEnd() throws IOException {
@@ -404,24 +273,10 @@ class ReaderImpl implements Reader {
 		hasLookahead = false;
 	}
 
-	private void skipObject() throws IOException {
-		if(hasBoolean()) skipBoolean();
-		else if(hasIntAny()) skipIntAny();
-		else if(hasFloat32()) skipFloat32();
-		else if(hasFloat64()) skipFloat64();
-		else if(hasString()) skipString(Integer.MAX_VALUE);
-		else if(hasBytes()) skipBytes(Integer.MAX_VALUE);
-		else if(hasList()) skipList();
-		else if(hasMap()) skipMap();
-		else if(hasStruct()) skipStruct();
-		else if(hasNull()) skipNull();
-		else throw new FormatException();
-	}
-
 	public boolean hasMap() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.MAP;
+		return next == MAP;
 	}
 
 	public void readMapStart() throws IOException {
@@ -450,14 +305,14 @@ class ReaderImpl implements Reader {
 	public boolean hasStruct() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.STRUCT;
+		return next == STRUCT;
 	}
 
 	public boolean hasStruct(int id) throws IOException {
 		if(id < 0 || id > 255) throw new IllegalArgumentException();
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.STRUCT && (nextStructId & 0xFF) == id;
+		return next == STRUCT && (nextStructId & 0xFF) == id;
 	}
 
 	public void readStructStart(int id) throws IOException {
@@ -483,7 +338,7 @@ class ReaderImpl implements Reader {
 	public boolean hasNull() throws IOException {
 		if(!hasLookahead) readLookahead();
 		if(eof) return false;
-		return next == Tag.NULL;
+		return next == NULL;
 	}
 
 	public void readNull() throws IOException {
diff --git a/briar-core/src/org/briarproject/serial/SerialComponentImpl.java b/briar-core/src/org/briarproject/serial/SerialComponentImpl.java
index 837eb3787ed115e9f4a3c295238ac686f39738c3..f94aeabbce7c57ad9d22014c52a0e470ad4ec2df 100644
--- a/briar-core/src/org/briarproject/serial/SerialComponentImpl.java
+++ b/briar-core/src/org/briarproject/serial/SerialComponentImpl.java
@@ -16,7 +16,7 @@ class SerialComponentImpl implements SerialComponent {
 	}
 
 	public int getSerialisedStructStartLength(int id) {
-		// STRUCT tag, ID
+		// STRUCT tag, 8-bit ID
 		return 2;
 	}
 
@@ -26,14 +26,7 @@ class SerialComponentImpl implements SerialComponent {
 	}
 
 	public int getSerialisedUniqueIdLength() {
-		// BYTES tag, length spec, bytes
-		return 1 + getSerialisedLengthSpecLength(UniqueId.LENGTH)
-				+ UniqueId.LENGTH;
-	}
-
-	private int getSerialisedLengthSpecLength(int length) {
-		if(length < 0) throw new IllegalArgumentException();
-		// Uint7, int16 or int32
-		return length <= Byte.MAX_VALUE ? 1 : length <= Short.MAX_VALUE ? 3 : 5;
+		// BYTES tag, 32-bit length, bytes
+		return 5 + UniqueId.LENGTH;
 	}
 }
diff --git a/briar-core/src/org/briarproject/serial/Tag.java b/briar-core/src/org/briarproject/serial/Tag.java
index 81597d6bab9b434d8b48ab600e44be0f82d0efa8..af7056186eee92717d4178daeaf60fa18fa79e71 100644
--- a/briar-core/src/org/briarproject/serial/Tag.java
+++ b/briar-core/src/org/briarproject/serial/Tag.java
@@ -2,19 +2,15 @@ package org.briarproject.serial;
 
 interface Tag {
 
-	byte FALSE = (byte) 0xFF;
-	byte TRUE = (byte) 0xFE;
-	byte INT8 = (byte) 0xFD;
-	byte INT16 = (byte) 0xFC;
-	byte INT32 = (byte) 0xFB;
-	byte INT64 = (byte) 0xFA;
-	byte FLOAT32 = (byte) 0xF9;
-	byte FLOAT64 = (byte) 0xF8;
-	byte STRING = (byte) 0xF7;
-	byte BYTES = (byte) 0xF6;
-	byte LIST = (byte) 0xF5;
-	byte MAP = (byte) 0xF4;
-	byte STRUCT = (byte) 0xF3;
-	byte END = (byte) 0xF2;
-	byte NULL = (byte) 0xF1;
+	byte FALSE = 0;
+	byte TRUE = 1;
+	byte INTEGER = 2;
+	byte FLOAT = 3;
+	byte STRING = 4;
+	byte BYTES = 5;
+	byte LIST = 6;
+	byte MAP = 7;
+	byte STRUCT = 8;
+	byte END = 9;
+	byte NULL = 10;
 }
diff --git a/briar-core/src/org/briarproject/serial/WriterImpl.java b/briar-core/src/org/briarproject/serial/WriterImpl.java
index 13a0e8ce95fa4fdd4952edf4ad74e90b7c967fc3..9e8ffe76603968f0950f1c974221dcb121d7e667 100644
--- a/briar-core/src/org/briarproject/serial/WriterImpl.java
+++ b/briar-core/src/org/briarproject/serial/WriterImpl.java
@@ -1,5 +1,11 @@
 package org.briarproject.serial;
 
+import static org.briarproject.serial.Tag.FALSE;
+import static org.briarproject.serial.Tag.FLOAT;
+import static org.briarproject.serial.Tag.INTEGER;
+import static org.briarproject.serial.Tag.STRING;
+import static org.briarproject.serial.Tag.TRUE;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
@@ -39,44 +45,16 @@ class WriterImpl implements Writer {
 	}
 
 	public void writeBoolean(boolean b) throws IOException {
-		if(b) write(Tag.TRUE);
-		else write(Tag.FALSE);
-	}
-
-	public void writeUint7(byte b) throws IOException {
-		if(b < 0) throw new IllegalArgumentException();
-		write(b);
-	}
-
-	public void writeInt8(byte b) throws IOException {
-		write(Tag.INT8);
-		write(b);
+		if(b) write(TRUE);
+		else write(FALSE);
 	}
 
-	public void writeInt16(short s) throws IOException {
-		write(Tag.INT16);
-		write((byte) (s >> 8));
-		write((byte) ((s << 8) >> 8));
+	public void writeInteger(long l) throws IOException {
+		write(INTEGER);
+		writeInt64(l);
 	}
 
-	public void writeInt32(int i) throws IOException {
-		write(Tag.INT32);
-		writeInt32Bits(i);
-	}
-
-	private void writeInt32Bits(int i) throws IOException {
-		write((byte) (i >> 24));
-		write((byte) ((i << 8) >> 24));
-		write((byte) ((i << 16) >> 24));
-		write((byte) ((i << 24) >> 24));
-	}
-
-	public void writeInt64(long l) throws IOException {
-		write(Tag.INT64);
-		writeInt64Bits(l);
-	}
-
-	private void writeInt64Bits(long l) throws IOException {
+	private void writeInt64(long l) throws IOException {
 		write((byte) (l >> 56));
 		write((byte) ((l << 8) >> 56));
 		write((byte) ((l << 16) >> 56));
@@ -87,41 +65,24 @@ class WriterImpl implements Writer {
 		write((byte) ((l << 56) >> 56));
 	}
 
-	public void writeIntAny(long l) throws IOException {
-		if(l >= 0 && l <= Byte.MAX_VALUE)
-			writeUint7((byte) l);
-		else if(l >= Byte.MIN_VALUE && l <= Byte.MAX_VALUE)
-			writeInt8((byte) l);
-		else if(l >= Short.MIN_VALUE && l <= Short.MAX_VALUE)
-			writeInt16((short) l);
-		else if(l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE)
-			writeInt32((int) l);
-		else writeInt64(l);
-	}
-
-	public void writeFloat32(float f) throws IOException {
-		write(Tag.FLOAT32);
-		writeInt32Bits(Float.floatToRawIntBits(f));
-	}
-
-	public void writeFloat64(double d) throws IOException {
-		write(Tag.FLOAT64);
-		writeInt64Bits(Double.doubleToRawLongBits(d));
+	public void writeFloat(double d) throws IOException {
+		write(FLOAT);
+		writeInt64(Double.doubleToRawLongBits(d));
 	}
 
 	public void writeString(String s) throws IOException {
 		byte[] b = s.getBytes("UTF-8");
-		write(Tag.STRING);
+		write(STRING);
 		writeLength(b.length);
 		write(b);
 	}
 
 	private void writeLength(int i) throws IOException {
 		assert i >= 0;
-		// Fun fact: it's never worth writing a length as an int8
-		if(i <= Byte.MAX_VALUE) writeUint7((byte) i);
-		else if(i <= Short.MAX_VALUE) writeInt16((short) i);
-		else writeInt32(i);
+		write((byte) (i >> 24));
+		write((byte) ((i << 8) >> 24));
+		write((byte) ((i << 16) >> 24));
+		write((byte) ((i << 24) >> 24));
 	}
 
 	public void writeBytes(byte[] b) throws IOException {
@@ -138,13 +99,14 @@ class WriterImpl implements Writer {
 
 	private void writeObject(Object o) throws IOException {
 		if(o instanceof Boolean) writeBoolean((Boolean) o);
-		else if(o instanceof Byte) writeIntAny((Byte) o);
-		else if(o instanceof Short) writeIntAny((Short) o);
-		else if(o instanceof Integer) writeIntAny((Integer) o);
-		else if(o instanceof Long) writeIntAny((Long) o);
-		else if(o instanceof Float) writeFloat32((Float) o);
-		else if(o instanceof Double) writeFloat64((Double) o);
+		else if(o instanceof Byte) writeInteger((Byte) o);
+		else if(o instanceof Short) writeInteger((Short) o);
+		else if(o instanceof Integer) writeInteger((Integer) o);
+		else if(o instanceof Long) writeInteger((Long) o);
+		else if(o instanceof Float) writeFloat((Float) o);
+		else if(o instanceof Double) writeFloat((Double) o);
 		else if(o instanceof String) writeString((String) o);
+		else if(o instanceof byte[]) writeBytes((byte[]) o);
 		else if(o instanceof Bytes) writeBytes(((Bytes) o).getBytes());
 		else if(o instanceof List<?>) writeList((List<?>) o);
 		else if(o instanceof Map<?, ?>) writeMap((Map<?, ?>) o);
diff --git a/briar-tests/src/org/briarproject/serial/ReaderImplTest.java b/briar-tests/src/org/briarproject/serial/ReaderImplTest.java
index da3bb7da0056bf447b93662d0746c0425f6fb00a..30c4eb1e4fafa590e933487317f35686b68a4449 100644
--- a/briar-tests/src/org/briarproject/serial/ReaderImplTest.java
+++ b/briar-tests/src/org/briarproject/serial/ReaderImplTest.java
@@ -7,7 +7,6 @@ import java.io.ByteArrayInputStream;
 import org.briarproject.BriarTestCase;
 import org.briarproject.api.FormatException;
 import org.briarproject.util.StringUtils;
-
 import org.junit.Test;
 
 public class ReaderImplTest extends BriarTestCase {
@@ -17,7 +16,7 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testReadBoolean() throws Exception {
-		setContents("FF" + "FE");
+		setContents("00" + "01");
 		assertFalse(r.readBoolean());
 		assertTrue(r.readBoolean());
 		assertTrue(r.eof());
@@ -25,160 +24,60 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testSkipBoolean() throws Exception {
-		setContents("FF" + "FE");
+		setContents("00" + "01");
 		r.skipBoolean();
 		r.skipBoolean();
 		assertTrue(r.eof());
 	}
 
 	@Test
-	public void testReadInt8() throws Exception {
-		setContents("FD00" + "FDFF" + "FD7F" + "FD80");
-		assertEquals((byte) 0, r.readInt8());
-		assertEquals((byte) -1, r.readInt8());
-		assertEquals(Byte.MAX_VALUE, r.readInt8());
-		assertEquals(Byte.MIN_VALUE, r.readInt8());
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testSkipInt8() throws Exception {
-		setContents("FD00");
-		r.skipInt8();
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testReadInt16() throws Exception {
-		setContents("FC0000" + "FCFFFF" + "FC7FFF" + "FC8000");
-		assertEquals((short) 0, r.readInt16());
-		assertEquals((short) -1, r.readInt16());
-		assertEquals(Short.MAX_VALUE, r.readInt16());
-		assertEquals(Short.MIN_VALUE, r.readInt16());
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testSkipInt16() throws Exception {
-		setContents("FC0000");
-		r.skipInt16();
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testReadInt32() throws Exception {
-		setContents("FB00000000" + "FBFFFFFFFF" + "FB7FFFFFFF" + "FB80000000");
-		assertEquals(0, r.readInt32());
-		assertEquals(-1, r.readInt32());
-		assertEquals(Integer.MAX_VALUE, r.readInt32());
-		assertEquals(Integer.MIN_VALUE, r.readInt32());
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testSkipInt32() throws Exception {
-		setContents("FB00000000");
-		r.skipInt32();
+	public void testReadInteger() throws Exception {
+		setContents("02" + "0000000000000000" + "02" + "FFFFFFFFFFFFFFFF"
+				+ "02" + "7FFFFFFFFFFFFFFF" + "02" + "8000000000000000");
+		assertEquals(0, r.readInteger());
+		assertEquals(-1, r.readInteger());
+		assertEquals(Long.MAX_VALUE, r.readInteger());
+		assertEquals(Long.MIN_VALUE, r.readInteger());
 		assertTrue(r.eof());
 	}
 
 	@Test
-	public void testReadInt64() throws Exception {
-		setContents("FA0000000000000000" + "FAFFFFFFFFFFFFFFFF"
-				+ "FA7FFFFFFFFFFFFFFF" + "FA8000000000000000");
-		assertEquals(0, r.readInt64());
-		assertEquals(-1, r.readInt64());
-		assertEquals(Long.MAX_VALUE, r.readInt64());
-		assertEquals(Long.MIN_VALUE, r.readInt64());
+	public void testSkipInteger() throws Exception {
+		setContents("02" + "0000000000000000");
+		r.skipInteger();
 		assertTrue(r.eof());
 	}
 
 	@Test
-	public void testSkipInt64() throws Exception {
-		setContents("FA0000000000000000");
-		r.skipInt64();
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testReadIntAny() throws Exception {
-		setContents("00" + "7F" + "FD80" + "FDFF" + "FC0080" + "FC7FFF"
-				+ "FB00008000" + "FB7FFFFFFF" + "FA0000000080000000");
-		assertEquals(0, r.readIntAny());
-		assertEquals(127, r.readIntAny());
-		assertEquals(-128, r.readIntAny());
-		assertEquals(-1, r.readIntAny());
-		assertEquals(128, r.readIntAny());
-		assertEquals(32767, r.readIntAny());
-		assertEquals(32768, r.readIntAny());
-		assertEquals(2147483647, r.readIntAny());
-		assertEquals(2147483648L, r.readIntAny());
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testSkipIntAny() throws Exception {
-		setContents("00" + "FD00" + "FC0000" + "FB00000000"
-				+ "FA0000000000000000");
-		r.skipIntAny();
-		r.skipIntAny();
-		r.skipIntAny();
-		r.skipIntAny();
-		r.skipIntAny();
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testReadFloat32() throws Exception {
+	public void testReadFloat() throws Exception {
 		// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
 		// http://steve.hollasch.net/cgindex/coding/ieeefloat.html
-		setContents("F900000000" + "F93F800000" + "F940000000" + "F9BF800000"
-				+ "F980000000" + "F9FF800000" + "F97F800000" + "F97FC00000");
-		assertEquals(0F, r.readFloat32());
-		assertEquals(1F, r.readFloat32());
-		assertEquals(2F, r.readFloat32());
-		assertEquals(-1F, r.readFloat32());
-		assertEquals(-0F, r.readFloat32());
-		assertEquals(Float.NEGATIVE_INFINITY, r.readFloat32());
-		assertEquals(Float.POSITIVE_INFINITY, r.readFloat32());
-		assertTrue(Float.isNaN(r.readFloat32()));
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testSkipFloat32() throws Exception {
-		setContents("F900000000");
-		r.skipFloat32();
-		assertTrue(r.eof());
-	}
-
-	@Test
-	public void testReadFloat64() throws Exception {
-		setContents("F80000000000000000" + "F83FF0000000000000"
-				+ "F84000000000000000" + "F8BFF0000000000000"
-				+ "F88000000000000000" + "F8FFF0000000000000"
-				+ "F87FF0000000000000" + "F87FF8000000000000");
-		assertEquals(0.0, r.readFloat64());
-		assertEquals(1.0, r.readFloat64());
-		assertEquals(2.0, r.readFloat64());
-		assertEquals(-1.0, r.readFloat64());
-		assertEquals(-0.0, r.readFloat64());
-		assertEquals(Double.NEGATIVE_INFINITY, r.readFloat64());
-		assertEquals(Double.POSITIVE_INFINITY, r.readFloat64());
-		assertTrue(Double.isNaN(r.readFloat64()));
+		setContents("03" + "0000000000000000" + "03" + "3FF0000000000000"
+				+ "03" + "4000000000000000" + "03" + "BFF0000000000000"
+				+ "03" + "8000000000000000" + "03" + "FFF0000000000000"
+				+ "03" + "7FF0000000000000" + "03" + "7FF8000000000000");
+		assertEquals(0.0, r.readFloat());
+		assertEquals(1.0, r.readFloat());
+		assertEquals(2.0, r.readFloat());
+		assertEquals(-1.0, r.readFloat());
+		assertEquals(-0.0, r.readFloat());
+		assertEquals(Double.NEGATIVE_INFINITY, r.readFloat());
+		assertEquals(Double.POSITIVE_INFINITY, r.readFloat());
+		assertTrue(Double.isNaN(r.readFloat()));
 		assertTrue(r.eof());
 	}
 
 	@Test
-	public void testSkipFloat64() throws Exception {
-		setContents("F80000000000000000");
-		r.skipFloat64();
+	public void testSkipFloat() throws Exception {
+		setContents("03" + "0000000000000000");
+		r.skipFloat();
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testReadString() throws Exception {
-		setContents("F703666F6F" + "F700");
+		// "foo" and the empty string
+		setContents("04" + "00000003" + "666F6F" + "04" + "00000000");
 		assertEquals("foo", r.readString(Integer.MAX_VALUE));
 		assertEquals("", r.readString(Integer.MAX_VALUE));
 		assertTrue(r.eof());
@@ -186,8 +85,11 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testReadStringMaxLength() throws Exception {
-		setContents("F703666F6F" + "F703666F6F");
+		// "foo" twice
+		setContents("04" + "00000003" + "666F6F" +
+				"04" + "00000003" + "666F6F");
 		assertEquals("foo", r.readString(3));
+		assertTrue(r.hasString());
 		try {
 			r.readString(2);
 			fail();
@@ -196,7 +98,8 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testSkipString() throws Exception {
-		setContents("F703666F6F" + "F700");
+		// "foo" and the empty string
+		setContents("04" + "00000003" + "666F6F" + "04" + "00000000");
 		r.skipString(Integer.MAX_VALUE);
 		r.skipString(Integer.MAX_VALUE);
 		assertTrue(r.eof());
@@ -204,8 +107,11 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testSkipStringMaxLength() throws Exception {
-		setContents("F703666F6F" + "F703666F6F");
+		// "foo" twice
+		setContents("04" + "00000003" + "666F6F" +
+				"04" + "00000003" + "666F6F");
 		r.skipString(3);
+		assertTrue(r.hasString());
 		try {
 			r.skipString(2);
 			fail();
@@ -214,7 +120,8 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testReadBytes() throws Exception {
-		setContents("F603010203" + "F600");
+		// {1, 2, 3} and {}
+		setContents("05" + "00000003" + "010203" + "05" + "00000000");
 		assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(Integer.MAX_VALUE));
 		assertArrayEquals(new byte[] {}, r.readBytes(Integer.MAX_VALUE));
 		assertTrue(r.eof());
@@ -222,8 +129,11 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testReadBytesMaxLength() throws Exception {
-		setContents("F603010203" + "F603010203");
+		// {1, 2, 3} twice
+		setContents("05" + "00000003" + "010203" +
+				"05" + "00000003" + "010203");
 		assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(3));
+		assertTrue(r.hasBytes());
 		try {
 			r.readBytes(2);
 			fail();
@@ -232,7 +142,8 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testSkipBytes() throws Exception {
-		setContents("F603010203" + "F600");
+		// {1, 2, 3} and {}
+		setContents("05" + "00000003" + "010203" + "05" + "00000000");
 		r.skipBytes(Integer.MAX_VALUE);
 		r.skipBytes(Integer.MAX_VALUE);
 		assertTrue(r.eof());
@@ -240,8 +151,11 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testSkipBytesMaxLength() throws Exception {
-		setContents("F603010203" + "F603010203");
+		// {1, 2, 3} twice
+		setContents("05" + "00000003" + "010203" +
+				"05" + "00000003" + "010203");
 		r.skipBytes(3);
+		assertTrue(r.hasBytes());
 		try {
 			r.skipBytes(2);
 			fail();
@@ -250,14 +164,17 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testReadList() throws Exception {
-		setContents("F5" + "01" + "F703666F6F" + "FC0080" + "F2");
+		// A list containing 2, "foo", and 128
+		setContents("06" + "02" + "0000000000000001" +
+				"04" + "00000003" + "666F6F" +
+				"02" + "0000000000000080" + "09");
 		r.readListStart();
 		assertFalse(r.hasListEnd());
-		assertEquals((byte) 1, r.readIntAny());
+		assertEquals(1, r.readInteger());
 		assertFalse(r.hasListEnd());
 		assertEquals("foo", r.readString(1000));
 		assertFalse(r.hasListEnd());
-		assertEquals((short) 128, r.readIntAny());
+		assertEquals(128, r.readInteger());
 		assertTrue(r.hasListEnd());
 		r.readListEnd();
 		assertTrue(r.eof());
@@ -265,19 +182,24 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testSkipList() throws Exception {
-		setContents("F5" + "01" + "F703666F6F" + "FC0080" + "F2");
+		// A list containing 2, "foo", and 128
+		setContents("06" + "02" + "0000000000000001" +
+				"04" + "00000003" + "666F6F" +
+				"02" + "0000000000000080" + "09");
 		r.skipList();
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testReadMap() throws Exception {
-		setContents("F4" + "F703666F6F" + "7B" + "F600" + "F1" + "F2");
+		// A map containing "foo" -> 123 and {} -> null
+		setContents("07" + "04" + "00000003" + "666F6F" +
+				"02" + "000000000000007B" + "05" + "00000000" + "0A" + "09");
 		r.readMapStart();
 		assertFalse(r.hasMapEnd());
 		assertEquals("foo", r.readString(1000));
 		assertFalse(r.hasMapEnd());
-		assertEquals((byte) 123, r.readIntAny());
+		assertEquals(123, r.readInteger());
 		assertFalse(r.hasMapEnd());
 		assertArrayEquals(new byte[] {}, r.readBytes(1000));
 		assertFalse(r.hasMapEnd());
@@ -290,7 +212,9 @@ public class ReaderImplTest extends BriarTestCase {
 
 	@Test
 	public void testSkipMap() throws Exception {
-		setContents("F4" + "F703666F6F" + "7B" + "F600" + "F1" + "F2");
+		// A map containing "foo" -> 123 and {} -> null
+		setContents("07" + "04" + "00000003" + "666F6F" +
+				"02" + "000000000000007B" + "05" + "00000000" + "0A" + "09");
 		r.skipMap();
 		assertTrue(r.eof());
 	}
@@ -298,7 +222,7 @@ public class ReaderImplTest extends BriarTestCase {
 	@Test
 	public void testReadStruct() throws Exception {
 		// Two empty structs with IDs 0 and 255
-		setContents("F300" + "F2" + "F3FF" + "F2");
+		setContents("0800" + "09" + "08FF" + "09");
 		r.readStructStart(0);
 		r.readStructEnd();
 		r.readStructStart(255);
@@ -309,7 +233,7 @@ public class ReaderImplTest extends BriarTestCase {
 	@Test
 	public void testSkipStruct() throws Exception {
 		// Two empty structs with IDs 0 and 255
-		setContents("F300" + "F2" + "F3FF" + "F2");
+		setContents("0800" + "09" + "08FF" + "09");
 		r.skipStruct();
 		r.skipStruct();
 		assertTrue(r.eof());
@@ -318,21 +242,21 @@ public class ReaderImplTest extends BriarTestCase {
 	@Test
 	public void testSkipNestedStructMapAndList() throws Exception {
 		// A struct containing a map containing two empty lists
-		setContents("F300" + "F4" + "F5" + "F2" + "F5" + "F2" + "F2" + "F2");
+		setContents("0800" + "07" + "06" + "09" + "06" + "09" + "09" + "09");
 		r.skipStruct();
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testReadNull() throws Exception {
-		setContents("F1");
+		setContents("0A");
 		r.readNull();
 		assertTrue(r.eof());
 	}
 
 	@Test
 	public void testSkipNull() throws Exception {
-		setContents("F1");
+		setContents("0A");
 		r.skipNull();
 		assertTrue(r.eof());
 	}
diff --git a/briar-tests/src/org/briarproject/serial/WriterImplTest.java b/briar-tests/src/org/briarproject/serial/WriterImplTest.java
index 4fdcebcf2adc29244b03b5c4380ac2c196bad3ea..f21da475a15697cb6b2cd879f701eebd796c7e92 100644
--- a/briar-tests/src/org/briarproject/serial/WriterImplTest.java
+++ b/briar-tests/src/org/briarproject/serial/WriterImplTest.java
@@ -10,7 +10,6 @@ import java.util.Map;
 
 import org.briarproject.BriarTestCase;
 import org.briarproject.util.StringUtils;
-
 import org.junit.Before;
 import org.junit.Test;
 
@@ -30,114 +29,43 @@ public class WriterImplTest extends BriarTestCase {
 		w.writeBoolean(true);
 		w.writeBoolean(false);
 		// TRUE tag, FALSE tag
-		checkContents("FE" + "FF");
-	}
-
-	@Test
-	public void testWriteUint7() throws IOException {
-		w.writeUint7((byte) 0);
-		w.writeUint7(Byte.MAX_VALUE);
-		// 0, 127
-		checkContents("00" + "7F");
-	}
-
-	@Test
-	public void testWriteInt8() throws IOException {
-		w.writeInt8((byte) 0);
-		w.writeInt8((byte) -1);
-		w.writeInt8(Byte.MIN_VALUE);
-		w.writeInt8(Byte.MAX_VALUE);
-		// INT8 tag, 0, INT8 tag, -1, INT8 tag, -128, INT8 tag, 127
-		checkContents("FD" + "00" + "FD" + "FF" + "FD" + "80" + "FD" + "7F");
-	}
-
-	@Test
-	public void testWriteInt16() throws IOException {
-		w.writeInt16((short) 0);
-		w.writeInt16((short) -1);
-		w.writeInt16(Short.MIN_VALUE);
-		w.writeInt16(Short.MAX_VALUE);
-		// INT16 tag, 0, INT16 tag, -1, INT16 tag, -32768, INT16 tag, 32767
-		checkContents("FC" + "0000" + "FC" + "FFFF" + "FC" + "8000"
-				+ "FC" + "7FFF");
+		checkContents("01" + "00");
 	}
 
 	@Test
-	public void testWriteInt32() throws IOException {
-		w.writeInt32(0);
-		w.writeInt32(-1);
-		w.writeInt32(Integer.MIN_VALUE);
-		w.writeInt32(Integer.MAX_VALUE);
-		// INT32 tag, 0, INT32 tag, -1, etc
-		checkContents("FB" + "00000000" + "FB" + "FFFFFFFF" + "FB" + "80000000"
-				+ "FB" + "7FFFFFFF");
+	public void testWriteInteger() throws IOException {
+		w.writeInteger(0);
+		w.writeInteger(-1);
+		w.writeInteger(Long.MIN_VALUE);
+		w.writeInteger(Long.MAX_VALUE);
+		// INTEGER tag, 0, INTEGER tag, -1, etc
+		checkContents("02" + "0000000000000000" + "02" + "FFFFFFFFFFFFFFFF"
+				+ "02" + "8000000000000000" + "02" + "7FFFFFFFFFFFFFFF");
 	}
 
 	@Test
-	public void testWriteInt64() throws IOException {
-		w.writeInt64(0);
-		w.writeInt64(-1);
-		w.writeInt64(Long.MIN_VALUE);
-		w.writeInt64(Long.MAX_VALUE);
-		// INT64 tag, 0, INT64 tag, -1, etc
-		checkContents("FA" + "0000000000000000" + "FA" + "FFFFFFFFFFFFFFFF"
-				+ "FA" + "8000000000000000" + "FA" + "7FFFFFFFFFFFFFFF");
-	}
-
-	@Test
-	public void testWriteIntAny() throws IOException {
-		w.writeIntAny(0); // uint7
-		w.writeIntAny(-1); // int8
-		w.writeIntAny(Byte.MAX_VALUE); // uint7
-		w.writeIntAny(Byte.MAX_VALUE + 1); // int16
-		w.writeIntAny(Short.MAX_VALUE); // int16
-		w.writeIntAny(Short.MAX_VALUE + 1); // int32
-		w.writeIntAny(Integer.MAX_VALUE); // int32
-		w.writeIntAny(Integer.MAX_VALUE + 1L); // int64
-		checkContents("00" + "FDFF" + "7F" + "FC0080" + "FC7FFF"
-				+ "FB00008000" + "FB7FFFFFFF" + "FA0000000080000000");
-	}
-
-	@Test
-	public void testWriteFloat32() throws IOException {
+	public void testWriteFloat() throws IOException {
 		// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
-		// 1 bit for sign, 8 for exponent, 23 for significand
-		w.writeFloat32(0F); // 0 0 0 -> 0x00000000
-		w.writeFloat32(1F); // 0 127 1 -> 0x3F800000
-		w.writeFloat32(2F); // 0 128 1 -> 0x40000000
-		w.writeFloat32(-1F); // 1 127 1 -> 0xBF800000
-		w.writeFloat32(-0F); // 1 0 0 -> 0x80000000
-		// http://steve.hollasch.net/cgindex/coding/ieeefloat.html
-		w.writeFloat32(Float.NEGATIVE_INFINITY); // 1 255 0 -> 0xFF800000
-		w.writeFloat32(Float.POSITIVE_INFINITY); // 0 255 0 -> 0x7F800000
-		w.writeFloat32(Float.NaN); // 0 255 1 -> 0x7FC00000
-		checkContents("F9" + "00000000" + "F9" + "3F800000" + "F9" + "40000000"
-				+ "F9" + "BF800000" + "F9" + "80000000" + "F9" + "FF800000"
-				+ "F9" + "7F800000" + "F9" + "7FC00000");
-	}
-
-	@Test
-	public void testWriteFloat64() throws IOException {
 		// 1 bit for sign, 11 for exponent, 52 for significand
-		w.writeFloat64(0.0); // 0 0 0 -> 0x0000000000000000
-		w.writeFloat64(1.0); // 0 1023 1 -> 0x3FF0000000000000
-		w.writeFloat64(2.0); // 0 1024 1 -> 0x4000000000000000
-		w.writeFloat64(-1.0); // 1 1023 1 -> 0xBFF0000000000000
-		w.writeFloat64(-0.0); // 1 0 0 -> 0x8000000000000000
-		w.writeFloat64(Double.NEGATIVE_INFINITY); // 1 2047 0 -> 0xFFF00000...
-		w.writeFloat64(Double.POSITIVE_INFINITY); // 0 2047 0 -> 0x7FF00000...
-		w.writeFloat64(Double.NaN); // 0 2047 1 -> 0x7FF8000000000000
-		checkContents("F8" + "0000000000000000" + "F8" + "3FF0000000000000"
-				+ "F8" + "4000000000000000" + "F8" + "BFF0000000000000"
-				+ "F8" + "8000000000000000" + "F8" + "FFF0000000000000"
-				+ "F8" + "7FF0000000000000" + "F8" + "7FF8000000000000");
+		w.writeFloat(0.0); // 0 0 0 -> 0x0000000000000000
+		w.writeFloat(1.0); // 0 1023 1 -> 0x3FF0000000000000
+		w.writeFloat(2.0); // 0 1024 1 -> 0x4000000000000000
+		w.writeFloat(-1.0); // 1 1023 1 -> 0xBFF0000000000000
+		w.writeFloat(-0.0); // 1 0 0 -> 0x8000000000000000
+		w.writeFloat(Double.NEGATIVE_INFINITY); // 1 2047 0 -> 0xFFF00000...
+		w.writeFloat(Double.POSITIVE_INFINITY); // 0 2047 0 -> 0x7FF00000...
+		w.writeFloat(Double.NaN); // 0 2047 1 -> 0x7FF8000000000000
+		checkContents("03" + "0000000000000000" + "03" + "3FF0000000000000"
+				+ "03" + "4000000000000000" + "03" + "BFF0000000000000"
+				+ "03" + "8000000000000000" + "03" + "FFF0000000000000"
+				+ "03" + "7FF0000000000000" + "03" + "7FF8000000000000");
 	}
 
 	@Test
 	public void testWriteString() throws IOException {
 		w.writeString("foo bar baz bam ");
-		// STRING tag, length 16 as uint7, UTF-8 bytes
-		checkContents("F7" + "10" + "666F6F206261722062617A2062616D20");
+		// STRING tag, length 16, UTF-8 bytes
+		checkContents("04" + "00000010" + "666F6F206261722062617A2062616D20");
 	}
 
 	@Test
@@ -145,17 +73,18 @@ public class WriterImplTest extends BriarTestCase {
 		w.writeBytes(new byte[] {
 				0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
 		});
-		// BYTES tag, length 16 as uint7, bytes
-		checkContents("F6" + "10" + "000102030405060708090A0B0C0D0E0F");
+		// BYTES tag, length 16, bytes
+		checkContents("05" + "00000010" + "000102030405060708090A0B0C0D0E0F");
 	}
 
 	@Test
 	public void testWriteList() throws IOException {
 		List<Object> l = new ArrayList<Object>();
-		for(int i = 0; i < 16; i++) l.add(i);
+		for(int i = 0; i < 3; i++) l.add(i);
 		w.writeList(l);
-		// LIST tag, elements as uint7, END tag
-		checkContents("F5" + "000102030405060708090A0B0C0D0E0F" + "F2");
+		// LIST tag, elements as integers, END tag
+		checkContents("06" + "02" + "0000000000000000" +
+				"02" + "0000000000000001" + "02" + "0000000000000002" + "09");
 	}
 
 	@Test
@@ -165,59 +94,66 @@ public class WriterImplTest extends BriarTestCase {
 		l.add(null);
 		l.add(2);
 		w.writeList(l);
-		// LIST tag, 1 as uint7, null, 2 as uint7, END tag
-		checkContents("F5" + "01" + "F1" + "02" + "F2");
+		// LIST tag, 1 as integer, NULL tag, 2 as integer, END tag
+		checkContents("06" + "02" + "0000000000000001" + "0A" +
+				"02" + "0000000000000002" + "09");
 	}
 
 	@Test
 	public void testWriteMap() throws IOException {
 		// Use LinkedHashMap to get predictable iteration order
 		Map<Object, Object> m = new LinkedHashMap<Object, Object>();
-		for(int i = 0; i < 16; i++) m.put(i, i + 1);
+		for(int i = 0; i < 4; i++) m.put(i, i + 1);
 		w.writeMap(m);
-		// MAP tag, entries as uint7, END tag
-		checkContents("F4" + "0001" + "0102" + "0203" + "0304" + "0405"
-				+ "0506" + "0607" + "0708" + "0809" + "090A" + "0A0B" + "0B0C"
-				+ "0C0D" + "0D0E" + "0E0F" + "0F10" + "F2");
+		// MAP tag, entries as integers, END tag
+		checkContents("07" + "02" + "0000000000000000" +
+				"02" + "0000000000000001" + "02" + "0000000000000001" +
+				"02" + "0000000000000002" + "02" + "0000000000000002" +
+				"02" + "0000000000000003" + "02" + "0000000000000003" +
+				"02" + "0000000000000004" + "09");
 	}
 
 	@Test
 	public void testWriteDelimitedList() throws IOException {
 		w.writeListStart();
-		w.writeIntAny((byte) 1); // Written as uint7
-		w.writeString("foo"); // Written as string
-		w.writeIntAny(128L); // Written as int16
+		w.writeInteger(1);
+		w.writeString("foo");
+		w.writeInteger(128);
 		w.writeListEnd();
-		// LIST tag, 1 as uint7, "foo" as string, 128 as int16, END tag
-		checkContents("F5" + "01" + "F703666F6F" + "FC0080" + "F2");
+		// LIST tag, 1 as integer, "foo" as string, 128 as integer, END tag
+		checkContents("06" + "02" + "0000000000000001" +
+				"04" + "00000003" + "666F6F" +
+				"02" + "0000000000000080" + "09");
 	}
 
 	@Test
 	public void testWriteDelimitedMap() throws IOException {
 		w.writeMapStart();
-		w.writeString("foo"); // Written as string
-		w.writeIntAny(123); // Written as uint7
-		w.writeBytes(new byte[0]); // Written as bytes
+		w.writeString("foo");
+		w.writeInteger(123);
+		w.writeBytes(new byte[0]);
 		w.writeNull();
 		w.writeMapEnd();
-		// MAP tag, "foo" as string, 123 as uint7, byte[0] as bytes,
-		// NULL tag, END tag
-		checkContents("F4" + "F703666F6F" + "7B" + "F600" + "F1" + "F2");
+		// MAP tag, "foo" as string, 123 as integer, {} as bytes, NULL tag,
+		// END tag
+		checkContents("07" + "04" + "00000003" + "666F6F" +
+				"02" + "000000000000007B" + "05" + "00000000" + "0A" + "09");
 	}
 
 	@Test
 	public void testWriteNestedMapsAndLists() throws IOException {
 		Map<Object, Object> m = new LinkedHashMap<Object, Object>();
-		m.put("foo", Integer.valueOf(123));
+		m.put("foo", 123);
 		List<Object> l = new ArrayList<Object>();
-		l.add(Byte.valueOf((byte) 1));
+		l.add((byte) 1);
 		Map<Object, Object> m1 = new LinkedHashMap<Object, Object>();
 		m1.put(m, l);
 		w.writeMap(m1);
-		// MAP tag, MAP tag, "foo" as string, 123 as uint7, END tag,
-		// LIST tag, 1 as uint7, END tag, END tag
-		checkContents("F4" + "F4" + "F703666F6F" + "7B" + "F2"
-				+ "F5" + "01" + "F2" + "F2");
+		// MAP tag, MAP tag, "foo" as string, 123 as integer, END tag,
+		// LIST tag, 1 as integer, END tag, END tag
+		checkContents("07" + "07" + "04" + "00000003" + "666F6F" +
+				"02" + "000000000000007B" + "09" + "06" +
+				"02" + "0000000000000001" + "09" + "09");
 	}
 
 	@Test
@@ -225,13 +161,13 @@ public class WriterImplTest extends BriarTestCase {
 		w.writeStructStart(123);
 		w.writeStructEnd();
 		// STRUCT tag, 123 as struct ID, END tag
-		checkContents("F3" + "7B" + "F2");
+		checkContents("08" + "7B" + "09");
 	}
 
 	@Test
 	public void testWriteNull() throws IOException {
 		w.writeNull();
-		checkContents("F1");
+		checkContents("0A");
 	}
 
 	private void checkContents(String hex) throws IOException {