diff --git a/api/net/sf/briar/api/serial/Reader.java b/api/net/sf/briar/api/serial/Reader.java index defa89ca374cf875c232f69b9a007174c4f86931..bcac81bde5540af0d11e55020ccfeb7aa720efee 100644 --- a/api/net/sf/briar/api/serial/Reader.java +++ b/api/net/sf/briar/api/serial/Reader.java @@ -56,4 +56,7 @@ public interface Reader { boolean hasNull() throws IOException; void readNull() throws IOException; + + boolean hasUserDefinedTag() throws IOException; + int readUserDefinedTag() throws IOException; } diff --git a/api/net/sf/briar/api/serial/Tag.java b/api/net/sf/briar/api/serial/Tag.java index 0cf44dbc271d71f6eb3c20c7f49eb1a7451bdd2f..09528efaf0c5ce552f4592cfa6dda10afc7b2f17 100644 --- a/api/net/sf/briar/api/serial/Tag.java +++ b/api/net/sf/briar/api/serial/Tag.java @@ -19,12 +19,13 @@ public interface Tag { public static final byte END = -15; // 1111 0001 public static final byte NULL = -16; // 1111 0000 + public static final byte USER = -32; // 1110 0000 + public static final int SHORT_MASK = 0xF0; // Match first four bits public static final int SHORT_STRING = 0x80; // 1000 xxxx public static final int SHORT_RAW = 0x90; // 1001 xxxx public static final int SHORT_LIST = 0xA0; // 1010 xxxx public static final int SHORT_MAP = 0xB0; // 1011 xxxx - public static final int USER_MASK = 0xE0; // Match first three bits - public static final int USER = 0xC0; // 110x xxxx - public static final byte USER_EXT = -32; // 1110 0000 + public static final int SHORT_USER_MASK = 0xE0; // Match first three bits + public static final int SHORT_USER = 0xC0; // 110x xxxx } diff --git a/api/net/sf/briar/api/serial/Writer.java b/api/net/sf/briar/api/serial/Writer.java index 284c5b5072df02bf3e479338ac5244e57c477cc7..e1c4a2721e5611d63c8af6ff13821c8ddf4d816c 100644 --- a/api/net/sf/briar/api/serial/Writer.java +++ b/api/net/sf/briar/api/serial/Writer.java @@ -34,4 +34,6 @@ public interface Writer { void writeMapEnd() throws IOException; void writeNull() throws IOException; + + void writeUserDefinedTag(int tag) throws IOException; } diff --git a/components/net/sf/briar/serial/ReaderImpl.java b/components/net/sf/briar/serial/ReaderImpl.java index 3d417d047f50eb36b90a99263f26f9d4c79fb15c..89ca72441dead46f2fe30548c6da3ce4ce83c978 100644 --- a/components/net/sf/briar/serial/ReaderImpl.java +++ b/components/net/sf/briar/serial/ReaderImpl.java @@ -459,4 +459,23 @@ class ReaderImpl implements Reader { if(!hasNull()) throw new FormatException(); readNext(true); } + + public boolean hasUserDefinedTag() throws IOException { + if(!started) readNext(true); + if(eof) return false; + return next == Tag.USER || + (next & Tag.SHORT_USER_MASK) == Tag.SHORT_USER; + } + + public int readUserDefinedTag() throws IOException { + if(!hasUserDefinedTag()) throw new FormatException(); + if(next == Tag.USER) { + readNext(false); + return readLength(); + } else { + int tag = 0xFF & next ^ Tag.SHORT_USER; + readNext(true); + return tag; + } + } } diff --git a/components/net/sf/briar/serial/WriterImpl.java b/components/net/sf/briar/serial/WriterImpl.java index 1a9359aec186bd5f8f6e761dcc96b5c2956bee96..5f5f06de8e2f29ef5f4975b6ff22c41e6e0539f5 100644 --- a/components/net/sf/briar/serial/WriterImpl.java +++ b/components/net/sf/briar/serial/WriterImpl.java @@ -211,4 +211,14 @@ class WriterImpl implements Writer { out.write(Tag.NULL); bytesWritten++; } + + public void writeUserDefinedTag(int tag) throws IOException { + if(tag < 0) throw new IllegalArgumentException(); + if(tag < 32) out.write((byte) (Tag.SHORT_USER | tag)); + else { + out.write(Tag.USER); + writeLength(tag); + } + bytesWritten++; + } } diff --git a/test/net/sf/briar/serial/ReaderImplTest.java b/test/net/sf/briar/serial/ReaderImplTest.java index ff1d5921187ed3eb2acfbf66abad0ad0e61c2066..0636a85b28bbba5516deefdaee3ee07c38bea0a5 100644 --- a/test/net/sf/briar/serial/ReaderImplTest.java +++ b/test/net/sf/briar/serial/ReaderImplTest.java @@ -316,6 +316,16 @@ public class ReaderImplTest extends TestCase { assertTrue(r.eof()); } + @Test + public void testReadUserDefinedTag() throws IOException { + setContents("C0" + "DF" + "E0" + "20" + "E0" + "FB7FFFFFFF"); + assertEquals(0, r.readUserDefinedTag()); + assertEquals(31, r.readUserDefinedTag()); + assertEquals(32, r.readUserDefinedTag()); + assertEquals(Integer.MAX_VALUE, r.readUserDefinedTag()); + assertTrue(r.eof()); + } + @Test public void testReadEmptyInput() throws IOException { setContents(""); diff --git a/test/net/sf/briar/serial/WriterImplTest.java b/test/net/sf/briar/serial/WriterImplTest.java index b5b91a427f64712afb3878a9c89b507700d875b4..a6f364d07adde13261392fc147fbf448e610fab9 100644 --- a/test/net/sf/briar/serial/WriterImplTest.java +++ b/test/net/sf/briar/serial/WriterImplTest.java @@ -37,7 +37,7 @@ public class WriterImplTest extends TestCase { @Test public void testWriteUint7() throws IOException { w.writeUint7((byte) 0); - w.writeUint7((byte) 127); + w.writeUint7(Byte.MAX_VALUE); // 0, 127 checkContents("00" + "7F"); } @@ -46,8 +46,8 @@ public class WriterImplTest extends TestCase { public void testWriteInt8() throws IOException { w.writeInt8((byte) 0); w.writeInt8((byte) -1); - w.writeInt8((byte) -128); - w.writeInt8((byte) 127); + w.writeInt8(Byte.MIN_VALUE); + w.writeInt8(Byte.MAX_VALUE); // INT8 tag, 0, INT8 tag, -1, INT8 tag, -128, INT8 tag, 127 checkContents("FD" + "00" + "FD" + "FF" + "FD" + "80" + "FD" + "7F"); } @@ -56,8 +56,8 @@ public class WriterImplTest extends TestCase { public void testWriteInt16() throws IOException { w.writeInt16((short) 0); w.writeInt16((short) -1); - w.writeInt16((short) -32768); - w.writeInt16((short) 32767); + w.writeInt16(Short.MIN_VALUE); + w.writeInt16(Short.MAX_VALUE); // INT16 tag, 0, INT16 tag, -1, INT16 tag, -32768, INT16 tag, 32767 checkContents("FC" + "0000" + "FC" + "FFFF" + "FC" + "8000" + "FC" + "7FFF"); @@ -67,8 +67,8 @@ public class WriterImplTest extends TestCase { public void testWriteInt32() throws IOException { w.writeInt32(0); w.writeInt32(-1); - w.writeInt32(-2147483648); - w.writeInt32(2147483647); + w.writeInt32(Integer.MIN_VALUE); + w.writeInt32(Integer.MAX_VALUE); // INT32 tag, 0, INT32 tag, -1, etc checkContents("FB" + "00000000" + "FB" + "FFFFFFFF" + "FB" + "80000000" + "FB" + "7FFFFFFF"); @@ -78,8 +78,8 @@ public class WriterImplTest extends TestCase { public void testWriteInt64() throws IOException { w.writeInt64(0L); w.writeInt64(-1L); - w.writeInt64(-9223372036854775808L); - w.writeInt64(9223372036854775807L); + w.writeInt64(Long.MIN_VALUE); + w.writeInt64(Long.MAX_VALUE); // INT64 tag, 0, INT64 tag, -1, etc checkContents("FA" + "0000000000000000" + "FA" + "FFFFFFFFFFFFFFFF" + "FA" + "8000000000000000" + "FA" + "7FFFFFFFFFFFFFFF"); @@ -87,15 +87,15 @@ public class WriterImplTest extends TestCase { @Test public void testWriteIntAny() throws IOException { - w.writeIntAny(0L); // uint7 - w.writeIntAny(127L); // uint7 - w.writeIntAny(-1L); // int8 - w.writeIntAny(128L); // int16 - w.writeIntAny(32767L); // int16 - w.writeIntAny(32768L); // int32 - w.writeIntAny(2147483647L); // int32 - w.writeIntAny(2147483648L); // int64 - checkContents("00" + "7F" + "FDFF" + "FC0080" + "FC7FFF" + w.writeIntAny(0); // uint7 + w.writeIntAny(-1); // int8 + w.writeIntAny(Byte.MAX_VALUE); // uint7 + w.writeIntAny(Byte.MAX_VALUE + 1); // int16 + w.writeIntAny(Short.MAX_VALUE); // int16 + w.writeIntAny(Short.MAX_VALUE + 1); // int32 + w.writeIntAny(Integer.MAX_VALUE); // int32 + w.writeIntAny(Integer.MAX_VALUE + 1L); // int64 + checkContents("00" + "FDFF" + "7F" + "FC0080" + "FC7FFF" + "FB00008000" + "FB7FFFFFFF" + "FA0000000080000000"); } @@ -283,6 +283,23 @@ public class WriterImplTest extends TestCase { checkContents("F0"); } + @Test + public void testWriteShortUserDefinedTag() throws IOException { + w.writeUserDefinedTag(0); + w.writeUserDefinedTag(31); + // SHORT_USER tag (3 bits), 0 (5 bits), SHORT_USER tag (3 bits), + // 31 (5 bits) + checkContents("C0" + "DF"); + } + + @Test + public void testWriteUserDefinedTag() throws IOException { + w.writeUserDefinedTag(32); + w.writeUserDefinedTag(Integer.MAX_VALUE); + // USER tag, 32 as uint7, USER tag, 2147483647 as int32 + checkContents("E0" + "20" + "E0" + "FB7FFFFFFF"); + } + private void checkContents(String hex) throws IOException { out.flush(); out.close();