From 6764ade4750e43643a0d1038e62c7aef9c3b915a Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Tue, 19 Nov 2013 18:05:44 +0000 Subject: [PATCH] Delimited structs - this will allow us to skip unrecognised structs. --- .../src/net/sf/briar/api/serial/Reader.java | 12 +- .../sf/briar/api/serial/SerialComponent.java | 6 +- .../src/net/sf/briar/api/serial/Writer.java | 5 +- .../sf/briar/messaging/AuthorFactoryImpl.java | 3 +- .../net/sf/briar/messaging/AuthorReader.java | 7 +- .../sf/briar/messaging/GroupFactoryImpl.java | 3 +- .../net/sf/briar/messaging/GroupReader.java | 3 +- .../briar/messaging/MessageFactoryImpl.java | 11 +- .../net/sf/briar/messaging/MessageReader.java | 8 +- .../sf/briar/messaging/PacketReaderImpl.java | 52 +++++-- .../sf/briar/messaging/PacketWriterImpl.java | 54 ++++--- .../messaging/SubscriptionUpdateReader.java | 9 +- .../src/net/sf/briar/serial/ReaderImpl.java | 136 ++++++++---------- .../sf/briar/serial/SerialComponentImpl.java | 24 ++-- briar-core/src/net/sf/briar/serial/Tag.java | 30 ++-- .../src/net/sf/briar/serial/WriterImpl.java | 14 +- .../briar/messaging/PacketReaderImplTest.java | 29 ++-- .../briar/messaging/PacketWriterImplTest.java | 8 +- .../net/sf/briar/serial/ReaderImplTest.java | 78 ++++++---- .../net/sf/briar/serial/WriterImplTest.java | 30 ++-- 20 files changed, 304 insertions(+), 218 deletions(-) diff --git a/briar-api/src/net/sf/briar/api/serial/Reader.java b/briar-api/src/net/sf/briar/api/serial/Reader.java index bdb0c3eff6..c81826f15a 100644 --- a/briar-api/src/net/sf/briar/api/serial/Reader.java +++ b/briar-api/src/net/sf/briar/api/serial/Reader.java @@ -40,30 +40,28 @@ public interface Reader { double readFloat64() throws IOException; boolean hasString() throws IOException; - String readString() throws IOException; String readString(int maxLength) throws IOException; boolean hasBytes() throws IOException; - byte[] readBytes() throws IOException; byte[] readBytes(int maxLength) throws IOException; boolean hasList() throws IOException; <E> List<E> readList(Class<E> e) throws IOException; - boolean hasListStart() throws IOException; void readListStart() throws IOException; boolean hasListEnd() throws IOException; void readListEnd() throws IOException; boolean hasMap() throws IOException; <K, V> Map<K, V> readMap(Class<K> k, Class<V> v) throws IOException; - boolean hasMapStart() throws IOException; void readMapStart() throws IOException; boolean hasMapEnd() throws IOException; void readMapEnd() throws IOException; + boolean hasStruct(int id) throws IOException; + void readStructStart(int id) throws IOException; + boolean hasStructEnd() throws IOException; + void readStructEnd() throws IOException; + boolean hasNull() throws IOException; void readNull() throws IOException; - - boolean hasStruct(int id) throws IOException; - void readStructId(int id) throws IOException; } diff --git a/briar-api/src/net/sf/briar/api/serial/SerialComponent.java b/briar-api/src/net/sf/briar/api/serial/SerialComponent.java index ae0c2f106a..0666a88db6 100644 --- a/briar-api/src/net/sf/briar/api/serial/SerialComponent.java +++ b/briar-api/src/net/sf/briar/api/serial/SerialComponent.java @@ -2,11 +2,13 @@ package net.sf.briar.api.serial; public interface SerialComponent { + int getSerialisedListStartLength(); + int getSerialisedListEndLength(); - int getSerialisedListStartLength(); + int getSerialisedStructStartLength(int id); - int getSerialisedStructIdLength(int id); + int getSerialisedStructEndLength(); int getSerialisedUniqueIdLength(); } diff --git a/briar-api/src/net/sf/briar/api/serial/Writer.java b/briar-api/src/net/sf/briar/api/serial/Writer.java index d13b711c61..ad2d338a43 100644 --- a/briar-api/src/net/sf/briar/api/serial/Writer.java +++ b/briar-api/src/net/sf/briar/api/serial/Writer.java @@ -35,7 +35,8 @@ public interface Writer { void writeMapStart() throws IOException; void writeMapEnd() throws IOException; - void writeNull() throws IOException; + void writeStructStart(int id) throws IOException; + void writeStructEnd() throws IOException; - void writeStructId(int id) throws IOException; + void writeNull() throws IOException; } diff --git a/briar-core/src/net/sf/briar/messaging/AuthorFactoryImpl.java b/briar-core/src/net/sf/briar/messaging/AuthorFactoryImpl.java index 67cfde1a17..8dc4ba94c9 100644 --- a/briar-core/src/net/sf/briar/messaging/AuthorFactoryImpl.java +++ b/briar-core/src/net/sf/briar/messaging/AuthorFactoryImpl.java @@ -41,9 +41,10 @@ class AuthorFactoryImpl implements AuthorFactory { private AuthorId getId(String name, byte[] publicKey) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(AUTHOR); + w.writeStructStart(AUTHOR); w.writeString(name); w.writeBytes(publicKey); + w.writeStructEnd(); MessageDigest messageDigest = crypto.getMessageDigest(); messageDigest.update(out.toByteArray()); return new AuthorId(messageDigest.digest()); diff --git a/briar-core/src/net/sf/briar/messaging/AuthorReader.java b/briar-core/src/net/sf/briar/messaging/AuthorReader.java index a2123b4378..3414b8aea6 100644 --- a/briar-core/src/net/sf/briar/messaging/AuthorReader.java +++ b/briar-core/src/net/sf/briar/messaging/AuthorReader.java @@ -23,12 +23,15 @@ class AuthorReader implements StructReader<Author> { } public Author readStruct(Reader r) throws IOException { + // Set up the reader DigestingConsumer digesting = new DigestingConsumer(messageDigest); - // Read and digest the data r.addConsumer(digesting); - r.readStructId(AUTHOR); + // Read and digest the data + r.readStructStart(AUTHOR); String name = r.readString(MAX_AUTHOR_NAME_LENGTH); byte[] publicKey = r.readBytes(MAX_PUBLIC_KEY_LENGTH); + r.readStructEnd(); + // Reset the reader r.removeConsumer(digesting); // Build and return the author AuthorId id = new AuthorId(messageDigest.digest()); diff --git a/briar-core/src/net/sf/briar/messaging/GroupFactoryImpl.java b/briar-core/src/net/sf/briar/messaging/GroupFactoryImpl.java index 81c0d53752..7bbc712005 100644 --- a/briar-core/src/net/sf/briar/messaging/GroupFactoryImpl.java +++ b/briar-core/src/net/sf/briar/messaging/GroupFactoryImpl.java @@ -36,9 +36,10 @@ class GroupFactoryImpl implements GroupFactory { public Group createGroup(String name, byte[] salt) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(GROUP); + w.writeStructStart(GROUP); w.writeString(name); w.writeBytes(salt); + w.writeStructEnd(); MessageDigest messageDigest = crypto.getMessageDigest(); messageDigest.update(out.toByteArray()); GroupId id = new GroupId(messageDigest.digest()); diff --git a/briar-core/src/net/sf/briar/messaging/GroupReader.java b/briar-core/src/net/sf/briar/messaging/GroupReader.java index ac3b20583d..20402c5ae2 100644 --- a/briar-core/src/net/sf/briar/messaging/GroupReader.java +++ b/briar-core/src/net/sf/briar/messaging/GroupReader.java @@ -26,11 +26,12 @@ class GroupReader implements StructReader<Group> { DigestingConsumer digesting = new DigestingConsumer(messageDigest); // Read and digest the data r.addConsumer(digesting); - r.readStructId(GROUP); + r.readStructStart(GROUP); String name = r.readString(MAX_GROUP_NAME_LENGTH); byte[] publicKey = null; if(r.hasNull()) r.readNull(); else publicKey = r.readBytes(MAX_PUBLIC_KEY_LENGTH); + r.readStructEnd(); r.removeConsumer(digesting); // Build and return the group GroupId id = new GroupId(messageDigest.digest()); diff --git a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java index b8e9f09f1c..810c8fd210 100644 --- a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java +++ b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java @@ -100,7 +100,7 @@ class MessageFactoryImpl implements MessageFactory { w.addConsumer(signingConsumer); } // Write the message - w.writeStructId(MESSAGE); + w.writeStructStart(MESSAGE); if(parent == null) w.writeNull(); else w.writeBytes(parent.getBytes()); if(group == null) w.writeNull(); @@ -109,7 +109,7 @@ class MessageFactoryImpl implements MessageFactory { else writeAuthor(w, author); w.writeString(contentType); long timestamp = clock.currentTimeMillis(); - w.writeInt64(timestamp); + w.writeIntAny(timestamp); byte[] salt = new byte[MESSAGE_SALT_LENGTH]; random.nextBytes(salt); w.writeBytes(salt); @@ -125,6 +125,7 @@ class MessageFactoryImpl implements MessageFactory { throw new IllegalArgumentException(); w.writeBytes(sig); } + w.writeStructEnd(); // Hash the message, including the signature, to get the message ID w.removeConsumer(digestingConsumer); MessageId id = new MessageId(messageDigest.digest()); @@ -143,14 +144,16 @@ class MessageFactoryImpl implements MessageFactory { } private void writeGroup(Writer w, Group g) throws IOException { - w.writeStructId(GROUP); + w.writeStructStart(GROUP); w.writeString(g.getName()); w.writeBytes(g.getSalt()); + w.writeStructEnd(); } private void writeAuthor(Writer w, Author a) throws IOException { - w.writeStructId(AUTHOR); + w.writeStructStart(AUTHOR); w.writeString(a.getName()); w.writeBytes(a.getPublicKey()); + w.writeStructEnd(); } } diff --git a/briar-core/src/net/sf/briar/messaging/MessageReader.java b/briar-core/src/net/sf/briar/messaging/MessageReader.java index db0e9598ca..c3a6978865 100644 --- a/briar-core/src/net/sf/briar/messaging/MessageReader.java +++ b/briar-core/src/net/sf/briar/messaging/MessageReader.java @@ -42,8 +42,8 @@ class MessageReader implements StructReader<UnverifiedMessage> { CountingConsumer counting = new CountingConsumer(MAX_PACKET_LENGTH); r.addConsumer(copying); r.addConsumer(counting); - // Read the initial tag - r.readStructId(MESSAGE); + // Read the start of the struct + r.readStructStart(MESSAGE); // Read the parent's message ID, if there is one MessageId parent = null; if(r.hasNull()) { @@ -64,7 +64,7 @@ class MessageReader implements StructReader<UnverifiedMessage> { // Read the content type String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH); // Read the timestamp - long timestamp = r.readInt64(); + long timestamp = r.readIntAny(); if(timestamp < 0) throw new FormatException(); // Read the salt byte[] salt = r.readBytes(MESSAGE_SALT_LENGTH); @@ -89,6 +89,8 @@ class MessageReader implements StructReader<UnverifiedMessage> { byte[] signature = null; if(author == null) r.readNull(); else signature = r.readBytes(MAX_SIGNATURE_LENGTH); + // Read the end of the struct + r.readStructEnd(); // The signature will be verified later r.removeConsumer(counting); r.removeConsumer(copying); diff --git a/briar-core/src/net/sf/briar/messaging/PacketReaderImpl.java b/briar-core/src/net/sf/briar/messaging/PacketReaderImpl.java index 682f1824d5..07b4bd8688 100644 --- a/briar-core/src/net/sf/briar/messaging/PacketReaderImpl.java +++ b/briar-core/src/net/sf/briar/messaging/PacketReaderImpl.java @@ -70,12 +70,17 @@ class PacketReaderImpl implements PacketReader { } public Ack readAck() throws IOException { + // Set up the reader Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); r.addConsumer(counting); - r.readStructId(ACK); + // 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 end of the struct + r.readStructEnd(); + // Reset the reader r.resetMaxBytesLength(); r.removeConsumer(counting); if(raw.isEmpty()) throw new FormatException(); @@ -103,12 +108,17 @@ class PacketReaderImpl implements PacketReader { } public Offer readOffer() throws IOException { + // Set up the reader Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); r.addConsumer(counting); - r.readStructId(OFFER); + // 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 end of the struct + r.readStructEnd(); + // Reset the reader r.resetMaxBytesLength(); r.removeConsumer(counting); if(raw.isEmpty()) throw new FormatException(); @@ -128,14 +138,19 @@ class PacketReaderImpl implements PacketReader { } public Request readRequest() throws IOException { + // Set up the reader Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); r.addConsumer(counting); - r.readStructId(REQUEST); + // Read the start of the struct + r.readStructStart(REQUEST); // There may be up to 7 bits of padding at the end of the bitmap int padding = r.readUint7(); if(padding > 7) throw new FormatException(); // Read the bitmap byte[] bitmap = r.readBytes(MAX_PACKET_LENGTH); + // Read the end of the struct + r.readStructEnd(); + // Reset the reader r.removeConsumer(counting); // Convert the bitmap into a BitSet int length = bitmap.length * 8 - padding; @@ -154,9 +169,10 @@ class PacketReaderImpl implements PacketReader { } public RetentionAck readRetentionAck() throws IOException { - r.readStructId(RETENTION_ACK); - long version = r.readInt64(); + r.readStructStart(RETENTION_ACK); + long version = r.readIntAny(); if(version < 0) throw new FormatException(); + r.readStructEnd(); return new RetentionAck(version); } @@ -165,11 +181,12 @@ class PacketReaderImpl implements PacketReader { } public RetentionUpdate readRetentionUpdate() throws IOException { - r.readStructId(RETENTION_UPDATE); - long retention = r.readInt64(); + r.readStructStart(RETENTION_UPDATE); + long retention = r.readIntAny(); if(retention < 0) throw new FormatException(); - long version = r.readInt64(); + long version = r.readIntAny(); if(version < 0) throw new FormatException(); + r.readStructEnd(); return new RetentionUpdate(retention, version); } @@ -178,9 +195,10 @@ class PacketReaderImpl implements PacketReader { } public SubscriptionAck readSubscriptionAck() throws IOException { - r.readStructId(SUBSCRIPTION_ACK); - long version = r.readInt64(); + r.readStructStart(SUBSCRIPTION_ACK); + long version = r.readIntAny(); if(version < 0) throw new FormatException(); + r.readStructEnd(); return new SubscriptionAck(version); } @@ -197,11 +215,12 @@ class PacketReaderImpl implements PacketReader { } public TransportAck readTransportAck() throws IOException { - r.readStructId(TRANSPORT_ACK); + r.readStructStart(TRANSPORT_ACK); byte[] b = r.readBytes(UniqueId.LENGTH); if(b.length < UniqueId.LENGTH) throw new FormatException(); - long version = r.readInt64(); + long version = r.readIntAny(); if(version < 0) throw new FormatException(); + r.readStructEnd(); return new TransportAck(new TransportId(b), version); } @@ -210,9 +229,11 @@ class PacketReaderImpl implements PacketReader { } public TransportUpdate readTransportUpdate() throws IOException { + // Set up the reader Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); r.addConsumer(counting); - r.readStructId(TRANSPORT_UPDATE); + // Read the start of the struct + r.readStructStart(TRANSPORT_UPDATE); // Read the transport ID byte[] b = r.readBytes(UniqueId.LENGTH); if(b.length < UniqueId.LENGTH) throw new FormatException(); @@ -223,8 +244,11 @@ class PacketReaderImpl implements PacketReader { r.resetMaxStringLength(); if(m.size() > MAX_PROPERTIES_PER_TRANSPORT) throw new FormatException(); // Read the version number - long version = r.readInt64(); + long version = r.readIntAny(); if(version < 0) throw new FormatException(); + // Read the end of the struct + r.readStructEnd(); + // Reset the reader r.removeConsumer(counting); // Build and return the transport update return new TransportUpdate(id, new TransportProperties(m), version); diff --git a/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java b/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java index 9cdc897b48..9b2607f8dd 100644 --- a/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java +++ b/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java @@ -50,27 +50,30 @@ class PacketWriterImpl implements PacketWriter { public int getMaxMessagesForAck(long capacity) { int packet = (int) Math.min(capacity, MAX_PACKET_LENGTH); - int overhead = serial.getSerialisedStructIdLength(ACK) + int overhead = serial.getSerialisedStructStartLength(ACK) + serial.getSerialisedListStartLength() - + serial.getSerialisedListEndLength(); + + serial.getSerialisedListEndLength() + + serial.getSerialisedStructEndLength(); int idLength = serial.getSerialisedUniqueIdLength(); return (packet - overhead) / idLength; } public int getMaxMessagesForOffer(long capacity) { int packet = (int) Math.min(capacity, MAX_PACKET_LENGTH); - int overhead = serial.getSerialisedStructIdLength(OFFER) + int overhead = serial.getSerialisedStructStartLength(OFFER) + serial.getSerialisedListStartLength() - + serial.getSerialisedListEndLength(); + + serial.getSerialisedListEndLength() + + serial.getSerialisedStructEndLength(); int idLength = serial.getSerialisedUniqueIdLength(); return (packet - overhead) / idLength; } public void writeAck(Ack a) throws IOException { - w.writeStructId(ACK); + w.writeStructStart(ACK); w.writeListStart(); for(MessageId m : a.getMessageIds()) w.writeBytes(m.getBytes()); w.writeListEnd(); + w.writeStructEnd(); if(flush) out.flush(); } @@ -80,10 +83,11 @@ class PacketWriterImpl implements PacketWriter { } public void writeOffer(Offer o) throws IOException { - w.writeStructId(OFFER); + w.writeStructStart(OFFER); w.writeListStart(); for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes()); w.writeListEnd(); + w.writeStructEnd(); if(flush) out.flush(); } @@ -101,57 +105,65 @@ class PacketWriterImpl implements PacketWriter { bitmap[offset] |= bit; } } - w.writeStructId(REQUEST); + w.writeStructStart(REQUEST); w.writeUint7((byte) (bytes * 8 - length)); w.writeBytes(bitmap); + w.writeStructEnd(); if(flush) out.flush(); } public void writeRetentionAck(RetentionAck a) throws IOException { - w.writeStructId(RETENTION_ACK); - w.writeInt64(a.getVersion()); + w.writeStructStart(RETENTION_ACK); + w.writeIntAny(a.getVersion()); + w.writeStructEnd(); if(flush) out.flush(); } public void writeRetentionUpdate(RetentionUpdate u) throws IOException { - w.writeStructId(RETENTION_UPDATE); - w.writeInt64(u.getRetentionTime()); - w.writeInt64(u.getVersion()); + w.writeStructStart(RETENTION_UPDATE); + w.writeIntAny(u.getRetentionTime()); + w.writeIntAny(u.getVersion()); + w.writeStructEnd(); if(flush) out.flush(); } public void writeSubscriptionAck(SubscriptionAck a) throws IOException { - w.writeStructId(SUBSCRIPTION_ACK); - w.writeInt64(a.getVersion()); + w.writeStructStart(SUBSCRIPTION_ACK); + w.writeIntAny(a.getVersion()); + w.writeStructEnd(); if(flush) out.flush(); } public void writeSubscriptionUpdate(SubscriptionUpdate u) throws IOException { - w.writeStructId(SUBSCRIPTION_UPDATE); + w.writeStructStart(SUBSCRIPTION_UPDATE); w.writeListStart(); for(Group g : u.getGroups()) { - w.writeStructId(GROUP); + w.writeStructStart(GROUP); w.writeString(g.getName()); w.writeBytes(g.getSalt()); + w.writeStructEnd(); } w.writeListEnd(); - w.writeInt64(u.getVersion()); + w.writeIntAny(u.getVersion()); + w.writeStructEnd(); if(flush) out.flush(); } public void writeTransportAck(TransportAck a) throws IOException { - w.writeStructId(TRANSPORT_ACK); + w.writeStructStart(TRANSPORT_ACK); w.writeBytes(a.getId().getBytes()); - w.writeInt64(a.getVersion()); + w.writeIntAny(a.getVersion()); + w.writeStructEnd(); if(flush) out.flush(); } public void writeTransportUpdate(TransportUpdate u) throws IOException { - w.writeStructId(TRANSPORT_UPDATE); + w.writeStructStart(TRANSPORT_UPDATE); w.writeBytes(u.getId().getBytes()); w.writeMap(u.getProperties()); - w.writeInt64(u.getVersion()); + w.writeIntAny(u.getVersion()); + w.writeStructEnd(); if(flush) out.flush(); } diff --git a/briar-core/src/net/sf/briar/messaging/SubscriptionUpdateReader.java b/briar-core/src/net/sf/briar/messaging/SubscriptionUpdateReader.java index 6312e4ea31..1ed20b5eda 100644 --- a/briar-core/src/net/sf/briar/messaging/SubscriptionUpdateReader.java +++ b/briar-core/src/net/sf/briar/messaging/SubscriptionUpdateReader.java @@ -26,9 +26,11 @@ class SubscriptionUpdateReader implements StructReader<SubscriptionUpdate> { } public SubscriptionUpdate readStruct(Reader r) throws IOException { + // Set up the reader Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); r.addConsumer(counting); - r.readStructId(SUBSCRIPTION_UPDATE); + // Read the start of the struct + r.readStructStart(SUBSCRIPTION_UPDATE); // Read the subscriptions List<Group> subs = new ArrayList<Group>(); r.readListStart(); @@ -36,8 +38,11 @@ class SubscriptionUpdateReader implements StructReader<SubscriptionUpdate> { subs.add(groupReader.readStruct(r)); r.readListEnd(); // Read the version number - long version = r.readInt64(); + long version = r.readIntAny(); if(version < 0) throw new FormatException(); + // Read the end of the struct + r.readStructEnd(); + // Reset the reader r.removeConsumer(counting); // Build and return the subscription update subs = Collections.unmodifiableList(subs); diff --git a/briar-core/src/net/sf/briar/serial/ReaderImpl.java b/briar-core/src/net/sf/briar/serial/ReaderImpl.java index 440940d6dc..6ab7a5b1a8 100644 --- a/briar-core/src/net/sf/briar/serial/ReaderImpl.java +++ b/briar-core/src/net/sf/briar/serial/ReaderImpl.java @@ -23,8 +23,8 @@ class ReaderImpl implements Reader { private final Collection<Consumer> consumers = new ArrayList<Consumer>(0); private boolean hasLookahead = false, eof = false; - private byte next, nextNext; - private byte[] buf = null; + private byte next, nextStructId; + private byte[] buf = new byte[8]; private int maxStringLength = Integer.MAX_VALUE; private int maxBytesLength = Integer.MAX_VALUE; @@ -33,42 +33,40 @@ class ReaderImpl implements Reader { } public boolean eof() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); return eof; } - private byte readLookahead(boolean eofAcceptable) throws IOException { + private void readLookahead() throws IOException { assert !eof; // 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(); eof = true; + return; } next = (byte) i; // If necessary, read another lookahead byte if(next == Tag.STRUCT) { i = in.read(); if(i == -1) throw new FormatException(); - nextNext = (byte) i; + nextStructId = (byte) i; } hasLookahead = true; - return next; } private void consumeLookahead() throws IOException { assert hasLookahead; for(Consumer c : consumers) { c.write(next); - if(next == Tag.STRUCT) c.write(nextNext); + if(next == Tag.STRUCT) c.write(nextStructId); } hasLookahead = false; } public void close() throws IOException { - buf = null; in.close(); } @@ -97,7 +95,7 @@ class ReaderImpl implements Reader { } public boolean hasBoolean() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.FALSE || next == Tag.TRUE; } @@ -109,7 +107,7 @@ class ReaderImpl implements Reader { } public boolean hasUint7() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next >= 0; } @@ -121,34 +119,37 @@ class ReaderImpl implements Reader { } public boolean hasInt8() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.INT8; } public byte readInt8() throws IOException { if(!hasInt8()) throw new FormatException(); - readLookahead(false); consumeLookahead(); - return next; + int i = in.read(); + if(i == -1) { + eof = true; + throw new FormatException(); + } + return (byte) i; } public boolean hasInt16() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.INT16; } public short readInt16() throws IOException { if(!hasInt16()) throw new FormatException(); - byte b1 = readLookahead(false); - byte b2 = readLookahead(false); consumeLookahead(); - return (short) (((b1 & 0xFF) << 8) | (b2 & 0xFF)); + readIntoBuffer(2); + return (short) (((buf[0] & 0xFF) << 8) | (buf[1] & 0xFF)); } public boolean hasInt32() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.INT32; } @@ -166,7 +167,7 @@ class ReaderImpl implements Reader { } private void readIntoBuffer(int length) throws IOException { - if(buf == null || buf.length < length) buf = new byte[length]; + if(buf.length < length) buf = new byte[length]; readIntoBuffer(buf, length); } @@ -177,17 +178,16 @@ class ReaderImpl implements Reader { int read = in.read(b, offset, length - offset); if(read == -1) { eof = true; - break; + throw new FormatException(); } offset += read; } - if(offset < length) throw new FormatException(); // Feed the hungry mouths for(Consumer c : consumers) c.write(b, 0, length); } public boolean hasInt64() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.INT64; } @@ -207,7 +207,7 @@ class ReaderImpl implements Reader { } public boolean hasIntAny() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next >= 0 || next == Tag.INT8 || next == Tag.INT16 || next == Tag.INT32 || next == Tag.INT64; @@ -224,7 +224,7 @@ class ReaderImpl implements Reader { } public boolean hasFloat32() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.FLOAT32; } @@ -236,7 +236,7 @@ class ReaderImpl implements Reader { } public boolean hasFloat64() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.FLOAT64; } @@ -248,15 +248,11 @@ class ReaderImpl implements Reader { } public boolean hasString() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.STRING; } - public String readString() throws IOException { - return readString(maxStringLength); - } - public String readString(int maxLength) throws IOException { if(!hasString()) throw new FormatException(); consumeLookahead(); @@ -269,30 +265,29 @@ class ReaderImpl implements Reader { private int readLength() throws IOException { if(!hasLength()) 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(); - throw new IllegalStateException(); + 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(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next >= 0 || next == Tag.INT8 || next == Tag.INT16 || next == Tag.INT32; } public boolean hasBytes() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.BYTES; } - public byte[] readBytes() throws IOException { - return readBytes(maxBytesLength); - } - public byte[] readBytes(int maxLength) throws IOException { if(!hasBytes()) throw new FormatException(); consumeLookahead(); @@ -305,7 +300,7 @@ class ReaderImpl implements Reader { } public boolean hasList() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.LIST; } @@ -320,13 +315,12 @@ class ReaderImpl implements Reader { } private boolean hasEnd() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.END; } private void readEnd() throws IOException { - if(!hasLookahead) throw new IllegalStateException(); if(!hasEnd()) throw new FormatException(); consumeLookahead(); } @@ -340,8 +334,8 @@ class ReaderImpl implements Reader { if(hasInt64()) return Long.valueOf(readInt64()); if(hasFloat32()) return Float.valueOf(readFloat32()); if(hasFloat64()) return Double.valueOf(readFloat64()); - if(hasString()) return readString(); - if(hasBytes()) return new Bytes(readBytes()); + 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()) { @@ -378,14 +372,8 @@ class ReaderImpl implements Reader { } } - public boolean hasListStart() throws IOException { - if(!hasLookahead) readLookahead(true); - if(eof) return false; - return next == Tag.LIST; - } - public void readListStart() throws IOException { - if(!hasListStart()) throw new FormatException(); + if(!hasList()) throw new FormatException(); consumeLookahead(); } @@ -398,7 +386,7 @@ class ReaderImpl implements Reader { } public boolean hasMap() throws IOException { - if(!hasLookahead) readLookahead(true); + if(!hasLookahead) readLookahead(); if(eof) return false; return next == Tag.MAP; } @@ -415,14 +403,8 @@ class ReaderImpl implements Reader { return Collections.unmodifiableMap(m); } - public boolean hasMapStart() throws IOException { - if(!hasLookahead) readLookahead(true); - if(eof) return false; - return next == Tag.MAP; - } - public void readMapStart() throws IOException { - if(!hasMapStart()) throw new FormatException(); + if(!hasMap()) throw new FormatException(); consumeLookahead(); } @@ -434,26 +416,34 @@ class ReaderImpl implements Reader { readEnd(); } - public boolean hasNull() throws IOException { - if(!hasLookahead) readLookahead(true); + 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.NULL; + return (nextStructId & 0xFF) == id; } - public void readNull() throws IOException { - if(!hasNull()) throw new FormatException(); + public void readStructStart(int id) throws IOException { + if(!hasStruct(id)) throw new FormatException(); consumeLookahead(); } - public boolean hasStruct(int id) throws IOException { - if(id < 0 || id > 255) throw new IllegalArgumentException(); - if(!hasLookahead) readLookahead(true); + public boolean hasStructEnd() throws IOException { + return hasEnd(); + } + + public void readStructEnd() throws IOException { + readEnd(); + } + + public boolean hasNull() throws IOException { + if(!hasLookahead) readLookahead(); if(eof) return false; - return id == (0xFF & nextNext); + return next == Tag.NULL; } - public void readStructId(int id) throws IOException { - if(!hasStruct(id)) throw new FormatException(); + public void readNull() throws IOException { + if(!hasNull()) throw new FormatException(); consumeLookahead(); } } diff --git a/briar-core/src/net/sf/briar/serial/SerialComponentImpl.java b/briar-core/src/net/sf/briar/serial/SerialComponentImpl.java index e55e94db0e..b3c5ba798a 100644 --- a/briar-core/src/net/sf/briar/serial/SerialComponentImpl.java +++ b/briar-core/src/net/sf/briar/serial/SerialComponentImpl.java @@ -5,31 +5,35 @@ import net.sf.briar.api.serial.SerialComponent; class SerialComponentImpl implements SerialComponent { + public int getSerialisedListStartLength() { + // LIST tag + return 1; + } + public int getSerialisedListEndLength() { // END tag return 1; } - public int getSerialisedListStartLength() { - // LIST tag - return 1; + public int getSerialisedStructStartLength(int id) { + // STRUCT tag, ID + return 2; } - public int getSerialisedStructIdLength(int id) { - if(id < 0 || id > 255) throw new IllegalArgumentException(); - return id < 32 ? 1 : 2; + public int getSerialisedStructEndLength() { + // END tag + return 1; } public int getSerialisedUniqueIdLength() { // BYTES tag, length spec, bytes return 1 + getSerialisedLengthSpecLength(UniqueId.LENGTH) - + UniqueId.LENGTH; + + UniqueId.LENGTH; } private int getSerialisedLengthSpecLength(int length) { if(length < 0) throw new IllegalArgumentException(); - if(length < 128) return 1; // Uint7 - if(length < Short.MAX_VALUE) return 3; // Int16 - return 5; // Int32 + // Uint7, int16 or int32 + return length <= Byte.MAX_VALUE ? 1 : length <= Short.MAX_VALUE ? 3 : 5; } } diff --git a/briar-core/src/net/sf/briar/serial/Tag.java b/briar-core/src/net/sf/briar/serial/Tag.java index 04b0e45478..67b6802d3d 100644 --- a/briar-core/src/net/sf/briar/serial/Tag.java +++ b/briar-core/src/net/sf/briar/serial/Tag.java @@ -2,19 +2,19 @@ package net.sf.briar.serial; interface Tag { - byte FALSE = (byte) 0xFF; // 1111 1111 - byte TRUE = (byte) 0xFE; // 1111 1110 - byte INT8 = (byte) 0xFD; // 1111 1101 - byte INT16 = (byte) 0xFC; // 1111 1100 - byte INT32 = (byte) 0xFB; // 1111 1011 - byte INT64 = (byte) 0xFA; // 1111 1010 - byte FLOAT32 = (byte) 0xF9; // 1111 1001 - byte FLOAT64 = (byte) 0xF8; // 1111 1000 - byte STRING = (byte) 0xF7; // 1111 0111 - byte BYTES = (byte) 0xF6; // 1111 0110 - byte LIST = (byte) 0xF5; // 1111 0111 - byte MAP = (byte) 0xF4; // 1111 0100 - byte END = (byte) 0xF3; // 1111 0011 - byte NULL = (byte) 0xF2; // 1111 0010 - byte STRUCT = (byte) 0xF1; // 1111 0001 + 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; } diff --git a/briar-core/src/net/sf/briar/serial/WriterImpl.java b/briar-core/src/net/sf/briar/serial/WriterImpl.java index aee13708f7..97635a5abc 100644 --- a/briar-core/src/net/sf/briar/serial/WriterImpl.java +++ b/briar-core/src/net/sf/briar/serial/WriterImpl.java @@ -177,16 +177,20 @@ class WriterImpl implements Writer { write(Tag.END); } - public void writeNull() throws IOException { - write(Tag.NULL); - } - - public void writeStructId(int id) throws IOException { + public void writeStructStart(int id) throws IOException { if(id < 0 || id > 255) throw new IllegalArgumentException(); write(Tag.STRUCT); write((byte) id); } + public void writeStructEnd() throws IOException { + write(Tag.END); + } + + public void writeNull() throws IOException { + write(Tag.NULL); + } + private void write(byte b) throws IOException { out.write(b); for(Consumer c : consumers) c.write(b); diff --git a/briar-tests/src/net/sf/briar/messaging/PacketReaderImplTest.java b/briar-tests/src/net/sf/briar/messaging/PacketReaderImplTest.java index a50b364485..43a2f4427c 100644 --- a/briar-tests/src/net/sf/briar/messaging/PacketReaderImplTest.java +++ b/briar-tests/src/net/sf/briar/messaging/PacketReaderImplTest.java @@ -165,14 +165,17 @@ public class PacketReaderImplTest extends BriarTestCase { private byte[] createAck(boolean tooBig) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(ACK); + w.writeStructStart(ACK); w.writeListStart(); while(out.size() + serial.getSerialisedUniqueIdLength() + + serial.getSerialisedListEndLength() + + serial.getSerialisedStructEndLength() < MAX_PACKET_LENGTH) { w.writeBytes(TestUtils.getRandomId()); } if(tooBig) w.writeBytes(TestUtils.getRandomId()); w.writeListEnd(); + w.writeStructEnd(); assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH); return out.toByteArray(); } @@ -180,23 +183,27 @@ public class PacketReaderImplTest extends BriarTestCase { private byte[] createEmptyAck() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(ACK); + w.writeStructStart(ACK); w.writeListStart(); w.writeListEnd(); + w.writeStructEnd(); return out.toByteArray(); } private byte[] createOffer(boolean tooBig) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(OFFER); + w.writeStructStart(OFFER); w.writeListStart(); while(out.size() + serial.getSerialisedUniqueIdLength() + + serial.getSerialisedListEndLength() + + serial.getSerialisedStructEndLength() < MAX_PACKET_LENGTH) { w.writeBytes(TestUtils.getRandomId()); } if(tooBig) w.writeBytes(TestUtils.getRandomId()); w.writeListEnd(); + w.writeStructEnd(); assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH); return out.toByteArray(); } @@ -204,24 +211,27 @@ public class PacketReaderImplTest extends BriarTestCase { private byte[] createEmptyOffer() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(OFFER); + w.writeStructStart(OFFER); w.writeListStart(); w.writeListEnd(); + w.writeStructEnd(); return out.toByteArray(); } private byte[] createRequest(boolean tooBig) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(REQUEST); - // Allow one byte for the STRUCT tag, one byte for the REQUEST tag, + w.writeStructStart(REQUEST); + // Allow one byte for the STRUCT tag, one byte for the struct ID, // one byte for the padding length as a uint7, one byte for the BYTES - // tag, and five bytes for the length of the byte array as an int32 - int size = MAX_PACKET_LENGTH - 9; + // tag, five bytes for the length of the byte array as an int32, and + // one byte for the END tag + int size = MAX_PACKET_LENGTH - 10; if(tooBig) size++; assertTrue(size > Short.MAX_VALUE); w.writeUint7((byte) 0); w.writeBytes(new byte[size]); + w.writeStructEnd(); assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH); return out.toByteArray(); } @@ -229,9 +239,10 @@ public class PacketReaderImplTest extends BriarTestCase { private byte[] createRequest(byte[] bitmap) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); - w.writeStructId(REQUEST); + w.writeStructStart(REQUEST); w.writeUint7((byte) 0); w.writeBytes(bitmap); + w.writeStructEnd(); return out.toByteArray(); } } diff --git a/briar-tests/src/net/sf/briar/messaging/PacketWriterImplTest.java b/briar-tests/src/net/sf/briar/messaging/PacketWriterImplTest.java index 2ef9af2e3b..197bed53e7 100644 --- a/briar-tests/src/net/sf/briar/messaging/PacketWriterImplTest.java +++ b/briar-tests/src/net/sf/briar/messaging/PacketWriterImplTest.java @@ -61,9 +61,9 @@ public class PacketWriterImplTest extends BriarTestCase { b.set(15); w.writeRequest(new Request(b, 16)); // STRUCT tag, struct ID 5, 0 as uint7, BYTES tag, length 2 as uint7, - // 0xD959 + // bitmap 0xD959, END tag byte[] output = out.toByteArray(); - assertEquals("F1" + "05" + "00" + "F6" + "02" + "D959", + assertEquals("F3" + "05" + "00" + "F6" + "02" + "D959" + "F2", StringUtils.toHexString(output)); } @@ -85,9 +85,9 @@ public class PacketWriterImplTest extends BriarTestCase { b.set(12); w.writeRequest(new Request(b, 13)); // STRUCT tag, struct ID 5, 3 as uint7, BYTES tag, length 2 as uint7, - // 0xD959 + // bitmap 0x59D8, END tag byte[] output = out.toByteArray(); - assertEquals("F1" + "05" + "03" + "F6" + "02" + "59D8", + assertEquals("F3" + "05" + "03" + "F6" + "02" + "59D8" + "F2", StringUtils.toHexString(output)); } } diff --git a/briar-tests/src/net/sf/briar/serial/ReaderImplTest.java b/briar-tests/src/net/sf/briar/serial/ReaderImplTest.java index ec8651d6a8..d2ef31cddb 100644 --- a/briar-tests/src/net/sf/briar/serial/ReaderImplTest.java +++ b/briar-tests/src/net/sf/briar/serial/ReaderImplTest.java @@ -122,8 +122,8 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadString() throws Exception { setContents("F703666F6F" + "F700"); - assertEquals("foo", r.readString()); - assertEquals("", r.readString()); + assertEquals("foo", r.readString(1000)); + assertEquals("", r.readString(1000)); assertTrue(r.eof()); } @@ -140,8 +140,8 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadBytes() throws Exception { setContents("F603010203" + "F600"); - assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes()); - assertArrayEquals(new byte[] {}, r.readBytes()); + assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(1000)); + assertArrayEquals(new byte[] {}, r.readBytes(1000)); assertTrue(r.eof()); } @@ -157,7 +157,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadList() throws Exception { - setContents("F5" + "01" + "F703666F6F" + "FC0080" + "F3"); + setContents("F5" + "01" + "F703666F6F" + "FC0080" + "F2"); List<Object> l = r.readList(Object.class); assertNotNull(l); assertEquals(3, l.size()); @@ -169,7 +169,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadListTypeSafe() throws Exception { - setContents("F5" + "01" + "02" + "03" + "F3"); + setContents("F5" + "01" + "02" + "03" + "F2"); List<Byte> l = r.readList(Byte.class); assertNotNull(l); assertEquals(3, l.size()); @@ -181,7 +181,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadListTypeSafeThrowsFormatException() throws Exception { - setContents("F5" + "01" + "F703666F6F" + "03" + "F3"); + setContents("F5" + "01" + "F703666F6F" + "03" + "F2"); // Trying to read a mixed list as a list of bytes should throw a // FormatException try { @@ -192,7 +192,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadMap() throws Exception { - setContents("F4" + "F703666F6F" + "7B" + "F600" + "F2" + "F3"); + setContents("F4" + "F703666F6F" + "7B" + "F600" + "F1" + "F2"); Map<Object, Object> m = r.readMap(Object.class, Object.class); assertNotNull(m); assertEquals(2, m.size()); @@ -205,7 +205,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadMapTypeSafe() throws Exception { - setContents("F4" + "F703666F6F" + "7B" + "F700" + "F2" + "F3"); + setContents("F4" + "F703666F6F" + "7B" + "F700" + "F1" + "F2"); Map<String, Byte> m = r.readMap(String.class, Byte.class); assertNotNull(m); assertEquals(2, m.size()); @@ -217,8 +217,8 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testMapKeysMustBeUnique() throws Exception { - setContents("F4" + "F703666F6F" + "01" + "F703626172" + "02" + "F3" - + "F4" + "F703666F6F" + "01" + "F703666F6F" + "02" + "F3"); + setContents("F4" + "F703666F6F" + "01" + "F703626172" + "02" + "F2" + + "F4" + "F703666F6F" + "01" + "F703666F6F" + "02" + "F2"); // The first map has unique keys Map<String, Byte> m = r.readMap(String.class, Byte.class); assertNotNull(m); @@ -234,13 +234,13 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadDelimitedListElements() throws Exception { - setContents("F5" + "01" + "F703666F6F" + "FC0080" + "F3"); - assertTrue(r.hasListStart()); + setContents("F5" + "01" + "F703666F6F" + "FC0080" + "F2"); + assertTrue(r.hasList()); r.readListStart(); assertFalse(r.hasListEnd()); assertEquals((byte) 1, r.readIntAny()); assertFalse(r.hasListEnd()); - assertEquals("foo", r.readString()); + assertEquals("foo", r.readString(1000)); assertFalse(r.hasListEnd()); assertEquals((short) 128, r.readIntAny()); assertTrue(r.hasListEnd()); @@ -250,7 +250,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadDelimitedListTypeSafe() throws Exception { - setContents("F5" + "01" + "02" + "03" + "F3"); + setContents("F5" + "01" + "02" + "03" + "F2"); List<Byte> l = r.readList(Byte.class); assertNotNull(l); assertEquals(3, l.size()); @@ -262,15 +262,15 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadDelimitedMapEntries() throws Exception { - setContents("F4" + "F703666F6F" + "7B" + "F600" + "F2" + "F3"); - assertTrue(r.hasMapStart()); + setContents("F4" + "F703666F6F" + "7B" + "F600" + "F1" + "F2"); + assertTrue(r.hasMap()); r.readMapStart(); assertFalse(r.hasMapEnd()); - assertEquals("foo", r.readString()); + assertEquals("foo", r.readString(1000)); assertFalse(r.hasMapEnd()); assertEquals((byte) 123, r.readIntAny()); assertFalse(r.hasMapEnd()); - assertArrayEquals(new byte[] {}, r.readBytes()); + assertArrayEquals(new byte[] {}, r.readBytes(1000)); assertFalse(r.hasMapEnd()); assertTrue(r.hasNull()); r.readNull(); @@ -281,7 +281,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadDelimitedMapTypeSafe() throws Exception { - setContents("F4" + "F703666F6F" + "7B" + "F700" + "F2" + "F3"); + setContents("F4" + "F703666F6F" + "7B" + "F700" + "F1" + "F2"); Map<String, Byte> m = r.readMap(String.class, Byte.class); assertNotNull(m); assertEquals(2, m.size()); @@ -294,8 +294,8 @@ public class ReaderImplTest extends BriarTestCase { @Test @SuppressWarnings("unchecked") public void testReadNestedMapsAndLists() throws Exception { - setContents("F4" + "F4" + "F703666F6F" + "7B" + "F3" - + "F5" + "01" + "F3" + "F3"); + setContents("F4" + "F4" + "F703666F6F" + "7B" + "F2" + + "F5" + "01" + "F2" + "F2"); Map<Object, Object> m = r.readMap(Object.class, Object.class); assertNotNull(m); assertEquals(1, m.size()); @@ -313,23 +313,34 @@ public class ReaderImplTest extends BriarTestCase { @Test - public void testMaxLengthAppliesInsideMap() throws Exception { - setContents("F4" + "F703666F6F" + "F603010203" + "F3"); + public void testMaxStringLengthAppliesInsideMap() throws Exception { + setContents("F4" + "F703666F6F" + "F603010203" + "F2"); r.setMaxStringLength(3); - r.setMaxBytesLength(3); Map<String, Bytes> m = r.readMap(String.class, Bytes.class); + assertTrue(r.eof()); String key = "foo"; Bytes value = new Bytes(new byte[] {1, 2, 3}); assertEquals(Collections.singletonMap(key, value), m); // The max string length should be applied inside the map - setContents("F4" + "F703666F6F" + "F603010203" + "F3"); + setContents("F4" + "F703666F6F" + "F603010203" + "F2"); r.setMaxStringLength(2); try { r.readMap(String.class, Bytes.class); fail(); } catch(FormatException expected) {} + } + + @Test + public void testMaxBytesLengthAppliesInsideMap() throws Exception { + setContents("F4" + "F703666F6F" + "F603010203" + "F2"); + r.setMaxBytesLength(3); + Map<String, Bytes> m = r.readMap(String.class, Bytes.class); + assertTrue(r.eof()); + String key = "foo"; + Bytes value = new Bytes(new byte[] {1, 2, 3}); + assertEquals(Collections.singletonMap(key, value), m); // The max bytes length should be applied inside the map - setContents("F4" + "F703666F6F" + "F603010203" + "F3"); + setContents("F4" + "F703666F6F" + "F603010203" + "F2"); r.setMaxBytesLength(2); try { r.readMap(String.class, Bytes.class); @@ -337,6 +348,19 @@ public class ReaderImplTest extends BriarTestCase { } catch(FormatException expected) {} } + @Test + public void testReadStruct() throws Exception { + // Two structs with IDs 0 and 255, each containing 1 as a uint7 + setContents("F300" + "01" + "F2" + "F3FF" + "01" + "F2"); + r.readStructStart(0); + assertEquals(1, r.readUint7()); + r.readStructEnd(); + r.readStructStart(255); + assertEquals(1, r.readUint7()); + r.readStructEnd(); + assertTrue(r.eof()); + } + @Test public void testReadEmptyInput() throws Exception { setContents(""); diff --git a/briar-tests/src/net/sf/briar/serial/WriterImplTest.java b/briar-tests/src/net/sf/briar/serial/WriterImplTest.java index 398c818411..502c5216a8 100644 --- a/briar-tests/src/net/sf/briar/serial/WriterImplTest.java +++ b/briar-tests/src/net/sf/briar/serial/WriterImplTest.java @@ -155,7 +155,7 @@ public class WriterImplTest extends BriarTestCase { for(int i = 0; i < 16; i++) l.add(i); w.writeList(l); // LIST tag, elements as uint7, END tag - checkContents("F5" + "000102030405060708090A0B0C0D0E0F" + "F3"); + checkContents("F5" + "000102030405060708090A0B0C0D0E0F" + "F2"); } @Test @@ -166,7 +166,7 @@ public class WriterImplTest extends BriarTestCase { l.add(2); w.writeList(l); // LIST tag, 1 as uint7, null, 2 as uint7, END tag - checkContents("F5" + "01" + "F2" + "02" + "F3"); + checkContents("F5" + "01" + "F1" + "02" + "F2"); } @Test @@ -178,7 +178,7 @@ public class WriterImplTest extends BriarTestCase { // 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" + "F3"); + + "0C0D" + "0D0E" + "0E0F" + "0F10" + "F2"); } @Test @@ -189,7 +189,7 @@ public class WriterImplTest extends BriarTestCase { w.writeIntAny(128L); // Written as int16 w.writeListEnd(); // LIST tag, 1 as uint7, "foo" as string, 128 as int16, END tag - checkContents("F5" + "01" + "F703666F6F" + "FC0080" + "F3"); + checkContents("F5" + "01" + "F703666F6F" + "FC0080" + "F2"); } @Test @@ -202,7 +202,7 @@ public class WriterImplTest extends BriarTestCase { w.writeMapEnd(); // MAP tag, "foo" as string, 123 as uint7, byte[0] as bytes, // NULL tag, END tag - checkContents("F4" + "F703666F6F" + "7B" + "F600" + "F2" + "F3"); + checkContents("F4" + "F703666F6F" + "7B" + "F600" + "F1" + "F2"); } @Test @@ -216,22 +216,22 @@ public class WriterImplTest extends BriarTestCase { 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" + "F3" - + "F5" + "01" + "F3" + "F3"); + checkContents("F4" + "F4" + "F703666F6F" + "7B" + "F2" + + "F5" + "01" + "F2" + "F2"); } @Test - public void testWriteNull() throws IOException { - w.writeNull(); - checkContents("F2"); + public void testWriteStruct() throws IOException { + w.writeStructStart(123); + w.writeStructEnd(); + // STRUCT tag, 123 as struct ID, END tag + checkContents("F3" + "7B" + "F2"); } @Test - public void testWriteStructId() throws IOException { - w.writeStructId(32); - w.writeStructId(255); - // STRUCT tag, 32 as uint8, STRUCT tag, 255 as uint8 - checkContents("F1" + "20" + "F1" + "FF"); + public void testWriteNull() throws IOException { + w.writeNull(); + checkContents("F1"); } private void checkContents(String hex) throws IOException { -- GitLab