From c3643a037b2abd3d9905809ed0dcf988d4e61bdf Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Tue, 12 Jul 2011 20:27:37 +0100
Subject: [PATCH] Added accessors for the amount of raw data read and written
 by readers and writers - this fixes a fixme in MessageParserImpl.

---
 api/net/sf/briar/api/crypto/KeyParser.java    |  4 ++--
 api/net/sf/briar/api/serial/Reader.java       |  1 +
 api/net/sf/briar/api/serial/Writer.java       |  1 +
 .../sf/briar/protocol/MessageParserImpl.java  | 23 ++++++++-----------
 .../net/sf/briar/serial/ReaderImpl.java       | 20 +++++++++++-----
 .../net/sf/briar/serial/WriterImpl.java       | 22 ++++++++++++++++++
 .../briar/protocol/BundleReadWriteTest.java   |  7 ++++--
 test/net/sf/briar/serial/ReaderImplTest.java  | 22 ++++++++++++++++++
 test/net/sf/briar/serial/WriterImplTest.java  |  1 +
 9 files changed, 78 insertions(+), 23 deletions(-)

diff --git a/api/net/sf/briar/api/crypto/KeyParser.java b/api/net/sf/briar/api/crypto/KeyParser.java
index 2363dee5d8..599c900828 100644
--- a/api/net/sf/briar/api/crypto/KeyParser.java
+++ b/api/net/sf/briar/api/crypto/KeyParser.java
@@ -1,9 +1,9 @@
 package net.sf.briar.api.crypto;
 
-import java.security.GeneralSecurityException;
 import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
 
 public interface KeyParser {
 
-	PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException;
+	PublicKey parsePublicKey(byte[] encodedKey) throws InvalidKeySpecException;
 }
diff --git a/api/net/sf/briar/api/serial/Reader.java b/api/net/sf/briar/api/serial/Reader.java
index 47bc385919..06fe30b8f3 100644
--- a/api/net/sf/briar/api/serial/Reader.java
+++ b/api/net/sf/briar/api/serial/Reader.java
@@ -9,6 +9,7 @@ public interface Reader {
 	boolean eof() throws IOException;
 	void setReadLimit(long limit);
 	void resetReadLimit();
+	long getRawBytesRead();
 	void close() throws IOException;
 
 	boolean hasBoolean() throws IOException;
diff --git a/api/net/sf/briar/api/serial/Writer.java b/api/net/sf/briar/api/serial/Writer.java
index 41f273333b..2efe55e306 100644
--- a/api/net/sf/briar/api/serial/Writer.java
+++ b/api/net/sf/briar/api/serial/Writer.java
@@ -6,6 +6,7 @@ import java.util.Map;
 
 public interface Writer {
 
+	long getRawBytesWritten();
 	void close() throws IOException;
 
 	void writeBoolean(boolean b) throws IOException;
diff --git a/components/net/sf/briar/protocol/MessageParserImpl.java b/components/net/sf/briar/protocol/MessageParserImpl.java
index f9b138a621..b2d01c36ef 100644
--- a/components/net/sf/briar/protocol/MessageParserImpl.java
+++ b/components/net/sf/briar/protocol/MessageParserImpl.java
@@ -7,6 +7,7 @@ import java.security.MessageDigest;
 import java.security.PublicKey;
 import java.security.Signature;
 import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
 
 import net.sf.briar.api.crypto.KeyParser;
 import net.sf.briar.api.protocol.AuthorId;
@@ -52,7 +53,6 @@ class MessageParserImpl implements MessageParser {
 		// Hash the author's nick and public key to get the author ID
 		String nick = r.readUtf8();
 		byte[] encodedKey = r.readRaw();
-		PublicKey publicKey = keyParser.parsePublicKey(encodedKey);
 		messageDigest.reset();
 		messageDigest.update(nick.getBytes("UTF-8"));
 		messageDigest.update((byte) 0); // Null separator
@@ -60,12 +60,17 @@ class MessageParserImpl implements MessageParser {
 		AuthorId author = new AuthorId(messageDigest.digest());
 		// Skip the message body
 		r.readRaw();
-		// Read the signature and work out how long the signed message is
-		byte[] sig = r.readRaw();
-		int length = raw.length - sig.length - bytesToEncode(sig.length);
 		// Verify the signature
+		int messageLength = (int) r.getRawBytesRead();
+		byte[] sig = r.readRaw();
+		PublicKey publicKey;
+		try {
+			publicKey = keyParser.parsePublicKey(encodedKey);
+		} catch(InvalidKeySpecException e) {
+			throw new FormatException();
+		}
 		signature.initVerify(publicKey);
-		signature.update(raw, 0, length);
+		signature.update(raw, 0, messageLength);
 		if(!signature.verify(sig)) throw new SignatureException();
 		// Hash the message, including the signature, to get the message ID
 		messageDigest.reset();
@@ -73,12 +78,4 @@ class MessageParserImpl implements MessageParser {
 		MessageId id = new MessageId(messageDigest.digest());
 		return new MessageImpl(id, parent, group, author, timestamp, raw);
 	}
-
-	// FIXME: Work out a better way of doing this
-	private int bytesToEncode(int i) {
-		if(i >= 0 && i <= Byte.MAX_VALUE) return 2;
-		if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) return 3;
-		if(i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) return 4;
-		return 6;
-	}
 }
diff --git a/components/net/sf/briar/serial/ReaderImpl.java b/components/net/sf/briar/serial/ReaderImpl.java
index b98383e0e6..dd9e4acf94 100644
--- a/components/net/sf/briar/serial/ReaderImpl.java
+++ b/components/net/sf/briar/serial/ReaderImpl.java
@@ -18,7 +18,7 @@ class ReaderImpl implements Reader {
 	private final InputStream in;
 	private boolean started = false, eof = false, readLimited = false;
 	private byte next;
-	private long readLimit = 0L;
+	private long rawBytesRead = 0L, readLimit = 0L;
 	private byte[] buf = null;
 
 	ReaderImpl(InputStream in) {
@@ -31,12 +31,12 @@ class ReaderImpl implements Reader {
 	}
 
 	private byte readNext(boolean eofAcceptable) throws IOException {
-		started = true;
 		int i = in.read();
 		if(i == -1) {
 			eof = true;
 			if(!eofAcceptable) throw new FormatException();
-		}
+		} else rawBytesRead++;
+		started = true;
 		if(i > 127) i -= 256;
 		next = (byte) i;
 		return next;
@@ -53,6 +53,12 @@ class ReaderImpl implements Reader {
 		readLimit = 0L;
 	}
 
+	public long getRawBytesRead() {
+		if(eof) return rawBytesRead;
+		else if(started) return rawBytesRead - 1L; // Exclude lookahead byte
+		else return 0L;
+	}
+
 	public void close() throws IOException {
 		in.close();
 	}
@@ -134,9 +140,11 @@ class ReaderImpl implements Reader {
 		if(buf == null || buf.length < length) buf = new byte[length];
 		buf[0] = next;
 		int offset = 1, read = 0;
-		while(offset < length && read != -1) {
+		while(offset < length) {
 			read = in.read(buf, offset, length - offset);
-			if(read != -1) offset += read;
+			if(read == -1) break;
+			offset += read;
+			rawBytesRead += read;
 		}
 		if(offset < length) throw new FormatException();
 		readNext(true);
@@ -307,7 +315,7 @@ class ReaderImpl implements Reader {
 			readNull();
 			return null;
 		}
-		throw new IllegalStateException();
+		throw new FormatException();
 	}
 
 	@SuppressWarnings("unchecked")
diff --git a/components/net/sf/briar/serial/WriterImpl.java b/components/net/sf/briar/serial/WriterImpl.java
index 18f1760780..a8cddfa1b3 100644
--- a/components/net/sf/briar/serial/WriterImpl.java
+++ b/components/net/sf/briar/serial/WriterImpl.java
@@ -13,11 +13,16 @@ import net.sf.briar.api.serial.Writer;
 class WriterImpl implements Writer {
 
 	private final OutputStream out;
+	private long rawBytesWritten = 0L;
 
 	WriterImpl(OutputStream out) {
 		this.out = out;
 	}
 
+	public long getRawBytesWritten() {
+		return rawBytesWritten;
+	}
+
 	public void close() throws IOException {
 		out.flush();
 		out.close();
@@ -26,27 +31,32 @@ class WriterImpl implements Writer {
 	public void writeBoolean(boolean b) throws IOException {
 		if(b) out.write(Tag.TRUE);
 		else out.write(Tag.FALSE);
+		rawBytesWritten++;
 	}
 
 	public void writeUint7(byte b) throws IOException {
 		if(b < 0) throw new IllegalArgumentException();
 		out.write(b);
+		rawBytesWritten++;
 	}
 
 	public void writeInt8(byte b) throws IOException {
 		out.write(Tag.INT8);
 		out.write(b);
+		rawBytesWritten += 2;
 	}
 
 	public void writeInt16(short s) throws IOException {
 		out.write(Tag.INT16);
 		out.write((byte) (s >> 8));
 		out.write((byte) ((s << 8) >> 8));
+		rawBytesWritten += 3;
 	}
 
 	public void writeInt32(int i) throws IOException {
 		out.write(Tag.INT32);
 		writeInt32Bits(i);
+		rawBytesWritten += 5;
 	}
 
 	private void writeInt32Bits(int i) throws IOException {
@@ -59,6 +69,7 @@ class WriterImpl implements Writer {
 	public void writeInt64(long l) throws IOException {
 		out.write(Tag.INT64);
 		writeInt64Bits(l);
+		rawBytesWritten += 9;
 	}
 
 	private void writeInt64Bits(long l) throws IOException {
@@ -87,11 +98,13 @@ class WriterImpl implements Writer {
 	public void writeFloat32(float f) throws IOException {
 		out.write(Tag.FLOAT32);
 		writeInt32Bits(Float.floatToRawIntBits(f));
+		rawBytesWritten += 5;
 	}
 
 	public void writeFloat64(double d) throws IOException {
 		out.write(Tag.FLOAT64);
 		writeInt64Bits(Double.doubleToRawLongBits(d));
+		rawBytesWritten += 9;
 	}
 
 	public void writeUtf8(String s) throws IOException {
@@ -99,12 +112,14 @@ class WriterImpl implements Writer {
 		byte[] b = s.getBytes("UTF-8");
 		writeIntAny(b.length);
 		out.write(b);
+		rawBytesWritten += b.length + 1;
 	}
 
 	public void writeRaw(byte[] b) throws IOException {
 		out.write(Tag.RAW);
 		writeIntAny(b.length);
 		out.write(b);
+		rawBytesWritten += b.length + 1;
 	}
 
 	public void writeRaw(Raw r) throws IOException {
@@ -113,6 +128,7 @@ class WriterImpl implements Writer {
 
 	public void writeList(List<?> l) throws IOException {
 		out.write(Tag.LIST_DEF);
+		rawBytesWritten++;
 		writeIntAny(l.size());
 		for(Object o : l) writeObject(o);
 	}
@@ -135,14 +151,17 @@ class WriterImpl implements Writer {
 
 	public void writeListStart() throws IOException {
 		out.write(Tag.LIST_INDEF);
+		rawBytesWritten++;
 	}
 
 	public void writeListEnd() throws IOException {
 		out.write(Tag.END);
+		rawBytesWritten++;
 	}
 
 	public void writeMap(Map<?, ?> m) throws IOException {
 		out.write(Tag.MAP_DEF);
+		rawBytesWritten++;
 		writeIntAny(m.size());
 		for(Entry<?, ?> e : m.entrySet()) {
 			writeObject(e.getKey());
@@ -152,13 +171,16 @@ class WriterImpl implements Writer {
 
 	public void writeMapStart() throws IOException {
 		out.write(Tag.MAP_INDEF);
+		rawBytesWritten++;
 	}
 
 	public void writeMapEnd() throws IOException {
 		out.write(Tag.END);
+		rawBytesWritten++;
 	}
 
 	public void writeNull() throws IOException {
 		out.write(Tag.NULL);
+		rawBytesWritten++;
 	}
 }
diff --git a/test/net/sf/briar/protocol/BundleReadWriteTest.java b/test/net/sf/briar/protocol/BundleReadWriteTest.java
index fcb26721e2..8a8851f925 100644
--- a/test/net/sf/briar/protocol/BundleReadWriteTest.java
+++ b/test/net/sf/briar/protocol/BundleReadWriteTest.java
@@ -12,6 +12,7 @@ import java.security.MessageDigest;
 import java.security.PublicKey;
 import java.security.Signature;
 import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.Arrays;
 import java.util.Collections;
@@ -82,10 +83,12 @@ public class BundleReadWriteTest extends TestCase {
 		keyPair = KeyPairGenerator.getInstance(KEY_PAIR_ALGO).generateKeyPair();
 		sig = Signature.getInstance(SIGNATURE_ALGO);
 		digest = MessageDigest.getInstance(DIGEST_ALGO);
+		final KeyFactory keyFactory = KeyFactory.getInstance(KEY_PAIR_ALGO);
 		keyParser = new KeyParser() {
-			public PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException {
+			public PublicKey parsePublicKey(byte[] encodedKey)
+			throws InvalidKeySpecException {
 				EncodedKeySpec e = new X509EncodedKeySpec(encodedKey);
-				return KeyFactory.getInstance(KEY_PAIR_ALGO).generatePublic(e);
+				return keyFactory.generatePublic(e);
 			}
 		};
 		assertEquals(digest.getDigestLength(), UniqueId.LENGTH);
diff --git a/test/net/sf/briar/serial/ReaderImplTest.java b/test/net/sf/briar/serial/ReaderImplTest.java
index a9e7bf5aa8..c87c00e401 100644
--- a/test/net/sf/briar/serial/ReaderImplTest.java
+++ b/test/net/sf/briar/serial/ReaderImplTest.java
@@ -3,6 +3,7 @@ package net.sf.briar.serial;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -343,6 +344,27 @@ public class ReaderImplTest extends TestCase {
 		assertTrue(r.eof());
 	}
 
+	@Test
+	public void testGetRawBytesRead() throws IOException {
+		setContents("F4" + "00" + "F4" + "00");
+		assertEquals(0L, r.getRawBytesRead());
+		Map<Object, Object> m = r.readMap(Object.class, Object.class);
+		assertEquals(2L, r.getRawBytesRead());
+		assertEquals(Collections.emptyMap(), m);
+		m = r.readMap(Object.class, Object.class);
+		assertEquals(4L, r.getRawBytesRead());
+		assertEquals(Collections.emptyMap(), m);
+		assertTrue(r.eof());
+		assertEquals(4L, r.getRawBytesRead());
+	}
+
+	@Test
+	public void testReadEmptyInput() throws IOException {
+		setContents("");
+		assertTrue(r.eof());
+		assertEquals(0L, r.getRawBytesRead());
+	}
+
 	private void setContents(String hex) {
 		in = new ByteArrayInputStream(StringUtils.fromHexString(hex));
 		r = new ReaderImpl(in);
diff --git a/test/net/sf/briar/serial/WriterImplTest.java b/test/net/sf/briar/serial/WriterImplTest.java
index f4afce160e..5d7eeec468 100644
--- a/test/net/sf/briar/serial/WriterImplTest.java
+++ b/test/net/sf/briar/serial/WriterImplTest.java
@@ -211,5 +211,6 @@ public class WriterImplTest extends TestCase {
 		byte[] expected = StringUtils.fromHexString(hex);
 		assertTrue(StringUtils.toHexString(out.toByteArray()),
 				Arrays.equals(expected, out.toByteArray()));
+		assertEquals(expected.length, w.getRawBytesWritten());
 	}
 }
-- 
GitLab