Added the ability to skip serialised objects.

This commit is contained in:
akwizgran
2013-11-19 21:28:53 +00:00
parent 6764ade475
commit 2e472c1d16
5 changed files with 380 additions and 334 deletions

View File

@@ -244,11 +244,16 @@ abstract class Connector extends Thread {
byte[] b = r.readBytes(UniqueId.LENGTH);
if(b.length != UniqueId.LENGTH) throw new FormatException();
TransportId id = new TransportId(b);
r.setMaxStringLength(MAX_PROPERTY_LENGTH);
Map<String, String> p = r.readMap(String.class, String.class);
r.resetMaxStringLength();
if(p.size() > MAX_PROPERTIES_PER_TRANSPORT)
throw new FormatException();
Map<String, String> p = new HashMap<String, String>();
r.readMapStart();
for(int i = 0; !r.hasMapEnd(); i++) {
if(i == MAX_PROPERTIES_PER_TRANSPORT)
throw new FormatException();
String key = r.readString(MAX_PROPERTY_LENGTH);
String value = r.readString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
r.readMapEnd();
remoteProps.put(id, new TransportProperties(p));
}
r.readListEnd();

View File

@@ -19,10 +19,10 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.briar.api.Bytes;
import net.sf.briar.api.FormatException;
import net.sf.briar.api.TransportId;
import net.sf.briar.api.TransportProperties;
@@ -75,22 +75,21 @@ class PacketReaderImpl implements PacketReader {
r.addConsumer(counting);
// Read the start of the struct
r.readStructStart(ACK);
// Read the message IDs as byte arrays
r.setMaxBytesLength(UniqueId.LENGTH);
List<Bytes> raw = r.readList(Bytes.class);
// Read the message IDs
List<MessageId> acked = new ArrayList<MessageId>();
r.readListStart();
while(!r.hasListEnd()) {
byte[] b = r.readBytes(UniqueId.LENGTH);
if(b.length != UniqueId.LENGTH)
throw new FormatException();
acked.add(new MessageId(b));
}
if(acked.isEmpty()) throw new FormatException();
r.readListEnd();
// Read the end of the struct
r.readStructEnd();
// Reset the reader
r.resetMaxBytesLength();
r.removeConsumer(counting);
if(raw.isEmpty()) throw new FormatException();
// Convert the byte arrays to message IDs
List<MessageId> acked = new ArrayList<MessageId>();
for(Bytes b : raw) {
if(b.getBytes().length != UniqueId.LENGTH)
throw new FormatException();
acked.add(new MessageId(b.getBytes()));
}
// Build and return the ack
return new Ack(Collections.unmodifiableList(acked));
}
@@ -113,22 +112,21 @@ class PacketReaderImpl implements PacketReader {
r.addConsumer(counting);
// Read the start of the struct
r.readStructStart(OFFER);
// Read the message IDs as byte arrays
r.setMaxBytesLength(UniqueId.LENGTH);
List<Bytes> raw = r.readList(Bytes.class);
// Read the message IDs
List<MessageId> messages = new ArrayList<MessageId>();
r.readListStart();
while(!r.hasListEnd()) {
byte[] b = r.readBytes(UniqueId.LENGTH);
if(b.length != UniqueId.LENGTH)
throw new FormatException();
messages.add(new MessageId(b));
}
if(messages.isEmpty()) throw new FormatException();
r.readListEnd();
// Read the end of the struct
r.readStructEnd();
// Reset the reader
r.resetMaxBytesLength();
r.removeConsumer(counting);
if(raw.isEmpty()) throw new FormatException();
// Convert the byte arrays to message IDs
List<MessageId> messages = new ArrayList<MessageId>();
for(Bytes b : raw) {
if(b.getBytes().length != UniqueId.LENGTH)
throw new FormatException();
messages.add(new MessageId(b.getBytes()));
}
// Build and return the offer
return new Offer(Collections.unmodifiableList(messages));
}
@@ -239,10 +237,16 @@ class PacketReaderImpl implements PacketReader {
if(b.length < UniqueId.LENGTH) throw new FormatException();
TransportId id = new TransportId(b);
// Read the transport properties
r.setMaxStringLength(MAX_PROPERTY_LENGTH);
Map<String, String> m = r.readMap(String.class, String.class);
r.resetMaxStringLength();
if(m.size() > MAX_PROPERTIES_PER_TRANSPORT) throw new FormatException();
Map<String, String> p = new HashMap<String, String>();
r.readMapStart();
for(int i = 0; !r.hasMapEnd(); i++) {
if(i == MAX_PROPERTIES_PER_TRANSPORT)
throw new FormatException();
String key = r.readString(MAX_PROPERTY_LENGTH);
String value = r.readString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
r.readMapEnd();
// Read the version number
long version = r.readIntAny();
if(version < 0) throw new FormatException();
@@ -251,6 +255,6 @@ class PacketReaderImpl implements PacketReader {
// Reset the reader
r.removeConsumer(counting);
// Build and return the transport update
return new TransportUpdate(id, new TransportProperties(m), version);
return new TransportUpdate(id, new TransportProperties(p), version);
}
}

View File

@@ -4,12 +4,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.briar.api.Bytes;
import net.sf.briar.api.FormatException;
import net.sf.briar.api.serial.Consumer;
import net.sf.briar.api.serial.Reader;
@@ -25,8 +20,6 @@ class ReaderImpl implements Reader {
private boolean hasLookahead = false, eof = false;
private byte next, nextStructId;
private byte[] buf = new byte[8];
private int maxStringLength = Integer.MAX_VALUE;
private int maxBytesLength = Integer.MAX_VALUE;
ReaderImpl(InputStream in) {
this.in = in;
@@ -70,22 +63,6 @@ class ReaderImpl implements Reader {
in.close();
}
public void setMaxStringLength(int length) {
maxStringLength = length;
}
public void resetMaxStringLength() {
maxStringLength = Integer.MAX_VALUE;
}
public void setMaxBytesLength(int length) {
maxBytesLength = length;
}
public void resetMaxBytesLength() {
maxBytesLength = Integer.MAX_VALUE;
}
public void addConsumer(Consumer c) {
consumers.add(c);
}
@@ -106,6 +83,11 @@ class ReaderImpl implements Reader {
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;
@@ -118,6 +100,11 @@ class ReaderImpl implements Reader {
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;
@@ -132,7 +119,19 @@ class ReaderImpl implements Reader {
eof = true;
throw new FormatException();
}
return (byte) i;
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();
}
hasLookahead = false;
}
public boolean hasInt16() throws IOException {
@@ -148,24 +147,6 @@ class ReaderImpl implements Reader {
return (short) (((buf[0] & 0xFF) << 8) | (buf[1] & 0xFF));
}
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);
}
private void readIntoBuffer(int length) throws IOException {
if(buf.length < length) buf = new byte[length];
readIntoBuffer(buf, length);
@@ -186,6 +167,47 @@ class ReaderImpl implements Reader {
for(Consumer c : consumers) c.write(b, 0, length);
}
public void skipInt16() throws IOException {
if(!hasInt16()) throw new FormatException();
hasLookahead = false;
skip(2);
}
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();
}
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);
}
public boolean hasInt64() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
@@ -206,6 +228,12 @@ class ReaderImpl implements Reader {
((buf[6] & 0xFFL) << 8) | (buf[7] & 0xFFL);
}
public void skipInt64() throws IOException {
if(!hasInt64()) throw new FormatException();
hasLookahead = false;
skip(8);
}
public boolean hasIntAny() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
@@ -223,6 +251,16 @@ class ReaderImpl implements Reader {
throw new IllegalStateException();
}
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 boolean hasFloat32() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
@@ -235,6 +273,12 @@ class ReaderImpl implements Reader {
return Float.intBitsToFloat(readInt32Bits());
}
public void skipFloat32() throws IOException {
if(!hasFloat32()) throw new FormatException();
hasLookahead = false;
skip(4);
}
public boolean hasFloat64() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
@@ -247,6 +291,12 @@ class ReaderImpl implements Reader {
return Double.longBitsToDouble(readInt64Bits());
}
public void skipFloat64() throws IOException {
if(!hasFloat64()) throw new FormatException();
hasLookahead = false;
skip(8);
}
public boolean hasString() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
@@ -282,6 +332,15 @@ class ReaderImpl implements Reader {
|| 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;
skip(length);
}
public boolean hasBytes() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
@@ -299,79 +358,21 @@ class ReaderImpl implements Reader {
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;
skip(length);
}
public boolean hasList() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.LIST;
}
public <E> List<E> readList(Class<E> e) throws IOException {
if(!hasList()) throw new FormatException();
consumeLookahead();
List<E> list = new ArrayList<E>();
while(!hasEnd()) list.add(readObject(e));
readEnd();
return Collections.unmodifiableList(list);
}
private boolean hasEnd() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.END;
}
private void readEnd() throws IOException {
if(!hasEnd()) throw new FormatException();
consumeLookahead();
}
private Object readObject() throws IOException {
if(hasBoolean()) return Boolean.valueOf(readBoolean());
if(hasUint7()) return Byte.valueOf(readUint7());
if(hasInt8()) return Byte.valueOf(readInt8());
if(hasInt16()) return Short.valueOf(readInt16());
if(hasInt32()) return Integer.valueOf(readInt32());
if(hasInt64()) return Long.valueOf(readInt64());
if(hasFloat32()) return Float.valueOf(readFloat32());
if(hasFloat64()) return Double.valueOf(readFloat64());
if(hasString()) return readString(maxStringLength);
if(hasBytes()) return new Bytes(readBytes(maxBytesLength));
if(hasList()) return readList(Object.class);
if(hasMap()) return readMap(Object.class, Object.class);
if(hasNull()) {
readNull();
return null;
}
throw new FormatException();
}
private <T> T readObject(Class<T> t) throws IOException {
try {
Object o = readObject();
// If this is a small integer type and we're expecting a larger
// integer type, promote before casting
if(o instanceof Byte) {
if(Short.class.isAssignableFrom(t))
return t.cast(Short.valueOf((Byte) o));
if(Integer.class.isAssignableFrom(t))
return t.cast(Integer.valueOf((Byte) o));
if(Long.class.isAssignableFrom(t))
return t.cast(Long.valueOf((Byte) o));
} else if(o instanceof Short) {
if(Integer.class.isAssignableFrom(t))
return t.cast(Integer.valueOf((Short) o));
if(Long.class.isAssignableFrom(t))
return t.cast(Long.valueOf((Short) o));
} else if(o instanceof Integer) {
if(Long.class.isAssignableFrom(t))
return t.cast(Long.valueOf((Integer) o));
}
return t.cast(o);
} catch(ClassCastException e) {
throw new FormatException();
}
}
public void readListStart() throws IOException {
if(!hasList()) throw new FormatException();
consumeLookahead();
@@ -381,28 +382,48 @@ class ReaderImpl implements Reader {
return hasEnd();
}
private boolean hasEnd() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.END;
}
public void readListEnd() throws IOException {
readEnd();
}
private void readEnd() throws IOException {
if(!hasEnd()) throw new FormatException();
consumeLookahead();
}
public void skipList() throws IOException {
if(!hasList()) throw new FormatException();
hasLookahead = false;
while(!hasListEnd()) skipObject();
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;
}
public <K, V> Map<K, V> readMap(Class<K> k, Class<V> v) throws IOException {
if(!hasMap()) throw new FormatException();
consumeLookahead();
Map<K, V> m = new HashMap<K, V>();
while(!hasEnd()) {
if(m.put(readObject(k), readObject(v)) != null)
throw new FormatException(); // Duplicate key
}
readEnd();
return Collections.unmodifiableMap(m);
}
public void readMapStart() throws IOException {
if(!hasMap()) throw new FormatException();
consumeLookahead();
@@ -416,11 +437,27 @@ class ReaderImpl implements Reader {
readEnd();
}
public void skipMap() throws IOException {
if(!hasMap()) throw new FormatException();
hasLookahead = false;
while(!hasMapEnd()) {
skipObject();
skipObject();
}
hasLookahead = false;
}
public boolean hasStruct() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
return next == Tag.STRUCT;
}
public boolean hasStruct(int id) throws IOException {
if(id < 0 || id > 255) throw new IllegalArgumentException();
if(!hasLookahead) readLookahead();
if(eof) return false;
return (nextStructId & 0xFF) == id;
return next == Tag.STRUCT && (nextStructId & 0xFF) == id;
}
public void readStructStart(int id) throws IOException {
@@ -436,6 +473,13 @@ class ReaderImpl implements Reader {
readEnd();
}
public void skipStruct() throws IOException {
if(!hasStruct()) throw new FormatException();
hasLookahead = false;
while(!hasStructEnd()) skipObject();
hasLookahead = false;
}
public boolean hasNull() throws IOException {
if(!hasLookahead) readLookahead();
if(eof) return false;
@@ -446,4 +490,9 @@ class ReaderImpl implements Reader {
if(!hasNull()) throw new FormatException();
consumeLookahead();
}
public void skipNull() throws IOException {
if(!hasNull()) throw new FormatException();
hasLookahead = false;
}
}