diff --git a/components/net/sf/briar/serial/ReaderImpl.java b/components/net/sf/briar/serial/ReaderImpl.java index 0f520d27e..29cbb0650 100644 --- a/components/net/sf/briar/serial/ReaderImpl.java +++ b/components/net/sf/briar/serial/ReaderImpl.java @@ -3,6 +3,7 @@ package net.sf.briar.serial; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -22,7 +23,7 @@ class ReaderImpl implements Reader { private Consumer[] consumers = new Consumer[] {}; private ObjectReader[] objectReaders = new ObjectReader[] {}; - private boolean started = false, eof = false; + private boolean hasLookahead = false, eof = false; private byte next, nextNext; private byte[] buf = null; @@ -31,26 +32,15 @@ class ReaderImpl implements Reader { } public boolean eof() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); return eof; } - private byte readNext(boolean eofAcceptable) throws IOException { + private byte readLookahead(boolean eofAcceptable) throws IOException { assert !eof; - if(started) { - for(Consumer c : consumers) { - c.write(next); - if(next == Tag.USER) c.write(nextNext); - } - } - started = true; - readLookahead(eofAcceptable); - return next; - } - - private void readLookahead(boolean eofAcceptable) throws IOException { - assert started; - // Read the lookahead byte + // If one or two lookahead bytes have been read, feed the consumers + if(hasLookahead) consumeLookahead(); + // Read a lookahead byte int i = in.read(); if(i == -1) { if(!eofAcceptable) throw new FormatException(); @@ -63,6 +53,17 @@ class ReaderImpl implements Reader { if(i == -1) throw new FormatException(); nextNext = (byte) i; } + hasLookahead = true; + return next; + } + + private void consumeLookahead() throws IOException { + assert hasLookahead; + for(Consumer c : consumers) { + c.write(next); + if(next == Tag.USER) c.write(nextNext); + } + hasLookahead = false; } public void close() throws IOException { @@ -109,68 +110,65 @@ class ReaderImpl implements Reader { } public boolean hasBoolean() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.FALSE || next == Tag.TRUE; } public boolean readBoolean() throws IOException { if(!hasBoolean()) throw new FormatException(); - int i = next; - readNext(true); - return i == Tag.TRUE; + consumeLookahead(); + return next == Tag.TRUE; } public boolean hasUint7() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next >= 0; } public byte readUint7() throws IOException { if(!hasUint7()) throw new FormatException(); - byte b = next; - readNext(true); - return b; + consumeLookahead(); + return next; } public boolean hasInt8() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.INT8; } public byte readInt8() throws IOException { if(!hasInt8()) throw new FormatException(); - byte b = readNext(false); - readNext(true); - return b; + readLookahead(false); + consumeLookahead(); + return next; } public boolean hasInt16() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.INT16; } public short readInt16() throws IOException { if(!hasInt16()) throw new FormatException(); - byte b1 = readNext(false); - byte b2 = readNext(false); - readNext(true); - int i = ((b1 & 0xFF) << 8) | (b2 & 0xFF); - return (short) i; + byte b1 = readLookahead(false); + byte b2 = readLookahead(false); + consumeLookahead(); + return (short) (((b1 & 0xFF) << 8) | (b2 & 0xFF)); } public boolean hasInt32() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.INT32; } public int readInt32() throws IOException { if(!hasInt32()) throw new FormatException(); - readNext(false); + consumeLookahead(); return readInt32Bits(); } @@ -186,12 +184,8 @@ class ReaderImpl implements Reader { } private void readIntoBuffer(byte[] b, int length) throws IOException { - b[0] = next; - int offset = 1; - if(next == Tag.USER) { - b[1] = nextNext; - offset = 2; - } + assert !hasLookahead; + int offset = 0; while(offset < length) { int read = in.read(b, offset, length - offset); if(read == -1) { @@ -203,18 +197,17 @@ class ReaderImpl implements Reader { if(offset < length) throw new FormatException(); // Feed the hungry mouths for(Consumer c : consumers) c.write(b, 0, length); - readLookahead(true); } public boolean hasInt64() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.INT64; } public long readInt64() throws IOException { if(!hasInt64()) throw new FormatException(); - readNext(false); + consumeLookahead(); return readInt64Bits(); } @@ -227,7 +220,7 @@ class ReaderImpl implements Reader { } public boolean hasIntAny() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next >= 0 || next == Tag.INT8 || next == Tag.INT16 || next == Tag.INT32 || next == Tag.INT64; @@ -244,31 +237,31 @@ class ReaderImpl implements Reader { } public boolean hasFloat32() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.FLOAT32; } public float readFloat32() throws IOException { if(!hasFloat32()) throw new FormatException(); - readNext(false); + consumeLookahead(); return Float.intBitsToFloat(readInt32Bits()); } public boolean hasFloat64() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.FLOAT64; } public double readFloat64() throws IOException { if(!hasFloat64()) throw new FormatException(); - readNext(false); + consumeLookahead(); return Double.longBitsToDouble(readInt64Bits()); } public boolean hasString() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.STRING || (next & Tag.SHORT_MASK) == Tag.SHORT_STRING; @@ -276,12 +269,11 @@ class ReaderImpl implements Reader { public String readString() throws IOException { if(!hasString()) throw new FormatException(); + consumeLookahead(); if(next == Tag.STRING) { - readNext(false); return readString(readLength()); } else { int length = 0xFF & next ^ Tag.SHORT_STRING; - readNext(length == 0); return readString(length); } } @@ -303,26 +295,25 @@ class ReaderImpl implements Reader { } private boolean hasLength() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next >= 0 || next == Tag.INT8 || next == Tag.INT16 || next == Tag.INT32; } public boolean hasBytes() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.BYTES || (next & Tag.SHORT_MASK) == Tag.SHORT_BYTES; } public byte[] readBytes() throws IOException { if(!hasBytes()) throw new FormatException(); + consumeLookahead(); if(next == Tag.BYTES) { - readNext(false); return readBytes(readLength()); } else { int length = 0xFF & next ^ Tag.SHORT_BYTES; - readNext(length == 0); return readBytes(length); } } @@ -336,7 +327,7 @@ class ReaderImpl implements Reader { } public boolean hasList() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.LIST || next == Tag.LIST_START || (next & Tag.SHORT_MASK) == Tag.SHORT_LIST; @@ -348,43 +339,41 @@ class ReaderImpl implements Reader { public List readList(Class e) throws IOException { if(!hasList()) throw new FormatException(); + consumeLookahead(); if(next == Tag.LIST) { - readNext(false); return readList(e, readLength()); } else if(next == Tag.LIST_START) { - readNext(false); List list = new ArrayList(); while(!hasEnd()) list.add(readObject(e)); readEnd(); return list; } else { int length = 0xFF & next ^ Tag.SHORT_LIST; - readNext(length == 0); return readList(e, length); } } private List readList(Class e, int length) throws IOException { assert length >= 0; + if(length == 0) return Collections.emptyList(); List list = new ArrayList(); for(int i = 0; i < length; i++) list.add(readObject(e)); return list; } private boolean hasEnd() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.END; } private void readEnd() throws IOException { - if(!started) throw new IllegalStateException(); + if(!hasLookahead) throw new IllegalStateException(); if(!hasEnd()) throw new FormatException(); - readNext(true); + consumeLookahead(); } private Object readObject() throws IOException { - if(!started) throw new IllegalStateException(); if(hasUserDefined()) return readUserDefined(); if(hasBoolean()) return Boolean.valueOf(readBoolean()); if(hasUint7()) return Byte.valueOf(readUint7()); @@ -406,11 +395,10 @@ class ReaderImpl implements Reader { } private boolean hasUserDefined() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; - if(next == Tag.USER) return true; - if((next & Tag.SHORT_USER_MASK) == Tag.SHORT_USER) return true; - return false; + return next == Tag.USER + || (next & Tag.SHORT_USER_MASK) == Tag.SHORT_USER; } private Object readUserDefined() throws IOException { @@ -430,14 +418,14 @@ class ReaderImpl implements Reader { } public boolean hasListStart() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.LIST_START; } public void readListStart() throws IOException { if(!hasListStart()) throw new FormatException(); - readNext(false); + consumeLookahead(); } public boolean hasListEnd() throws IOException { @@ -449,7 +437,7 @@ class ReaderImpl implements Reader { } public boolean hasMap() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.MAP || next == Tag.MAP_START || (next & Tag.SHORT_MASK) == Tag.SHORT_MAP; @@ -461,18 +449,16 @@ class ReaderImpl implements Reader { public Map readMap(Class k, Class v) throws IOException { if(!hasMap()) throw new FormatException(); + consumeLookahead(); if(next == Tag.MAP) { - readNext(false); return readMap(k, v, readLength()); } else if(next == Tag.MAP_START) { - readNext(false); Map m = new HashMap(); while(!hasEnd()) m.put(readObject(k), readObject(v)); readEnd(); return m; } else { int size = 0xFF & next ^ Tag.SHORT_MAP; - readNext(size == 0); return readMap(k, v, size); } } @@ -480,20 +466,21 @@ class ReaderImpl implements Reader { private Map readMap(Class k, Class v, int size) throws IOException { assert size >= 0; + if(size == 0) return Collections.emptyMap(); Map m = new HashMap(); for(int i = 0; i < size; i++) m.put(readObject(k), readObject(v)); return m; } public boolean hasMapStart() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.MAP_START; } public void readMapStart() throws IOException { if(!hasMapStart()) throw new FormatException(); - readNext(false); + consumeLookahead(); } public boolean hasMapEnd() throws IOException { @@ -505,19 +492,19 @@ class ReaderImpl implements Reader { } public boolean hasNull() throws IOException { - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; return next == Tag.NULL; } public void readNull() throws IOException { if(!hasNull()) throw new FormatException(); - readNext(true); + consumeLookahead(); } public boolean hasUserDefined(int tag) throws IOException { if(tag < 0 || tag > 255) throw new IllegalArgumentException(); - if(!started) readNext(true); + if(!hasLookahead) readLookahead(true); if(eof) return false; if(next == Tag.USER) return tag == (0xFF & nextNext); @@ -540,6 +527,6 @@ class ReaderImpl implements Reader { public void readUserDefinedTag(int tag) throws IOException { if(!hasUserDefined(tag)) throw new FormatException(); - readNext(false); + consumeLookahead(); } }