mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Modifying Protocol Buffers (or Thrift, or MessagePack, or any of the free ASN.1 implementations I could find) to support length constraints was more work than writing a custom serialisation format, so I wrote a custom format.
This commit is contained in:
@@ -15,6 +15,5 @@
|
||||
<classpathentry kind="lib" path="lib/test/hamcrest-core-1.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/test/hamcrest-library-1.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/test/jmock-2.5.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/protobuf.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +0,0 @@
|
||||
package protocol;
|
||||
|
||||
option java_package = "net.sf.briar.api.protocol";
|
||||
|
||||
message TransportDetails {
|
||||
|
||||
message TransportDetail {
|
||||
required string key = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
|
||||
repeated TransportDetail details = 1;
|
||||
}
|
||||
9
api/net/sf/briar/api/serial/FormatException.java
Normal file
9
api/net/sf/briar/api/serial/FormatException.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class FormatException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 2274966775687766337L;
|
||||
|
||||
}
|
||||
6
api/net/sf/briar/api/serial/Raw.java
Normal file
6
api/net/sf/briar/api/serial/Raw.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
public interface Raw {
|
||||
|
||||
byte[] getBytes();
|
||||
}
|
||||
54
api/net/sf/briar/api/serial/Reader.java
Normal file
54
api/net/sf/briar/api/serial/Reader.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface Reader {
|
||||
|
||||
boolean eof() throws IOException;
|
||||
|
||||
boolean hasBoolean() throws IOException;
|
||||
boolean readBoolean() throws IOException;
|
||||
|
||||
boolean hasUint7() throws IOException;
|
||||
byte readUint7() throws IOException;
|
||||
boolean hasInt8() throws IOException;
|
||||
byte readInt8() throws IOException;
|
||||
boolean hasInt16() throws IOException;
|
||||
short readInt16() throws IOException;
|
||||
boolean hasInt32() throws IOException;
|
||||
int readInt32() throws IOException;
|
||||
boolean hasInt64() throws IOException;
|
||||
long readInt64() throws IOException;
|
||||
boolean hasIntAny() throws IOException;
|
||||
long readIntAny() throws IOException;
|
||||
|
||||
boolean hasFloat32() throws IOException;
|
||||
float readFloat32() throws IOException;
|
||||
boolean hasFloat64() throws IOException;
|
||||
double readFloat64() throws IOException;
|
||||
|
||||
boolean hasUtf8() throws IOException;
|
||||
String readUtf8() throws IOException;
|
||||
String readUtf8(int maxLength) throws IOException;
|
||||
|
||||
boolean hasRaw() throws IOException;
|
||||
byte[] readRaw() throws IOException;
|
||||
byte[] readRaw(int maxLength) throws IOException;
|
||||
|
||||
// FIXME: Add type-safe readers and iterator readers
|
||||
|
||||
boolean hasList(boolean definite) throws IOException;
|
||||
List<?> readList(boolean definite) throws IOException;
|
||||
boolean hasList() throws IOException;
|
||||
List<?> readList() throws IOException;
|
||||
|
||||
boolean hasMap(boolean definite) throws IOException;
|
||||
Map<?, ?> readMap(boolean definite) throws IOException;
|
||||
boolean hasMap() throws IOException;
|
||||
Map<?, ?> readMap() throws IOException;
|
||||
|
||||
boolean hasNull() throws IOException;
|
||||
void readNull() throws IOException;
|
||||
}
|
||||
8
api/net/sf/briar/api/serial/ReaderFactory.java
Normal file
8
api/net/sf/briar/api/serial/ReaderFactory.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface ReaderFactory {
|
||||
|
||||
Reader createReader(InputStream in);
|
||||
}
|
||||
13
api/net/sf/briar/api/serial/Tag.java
Normal file
13
api/net/sf/briar/api/serial/Tag.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
public interface Tag {
|
||||
|
||||
// FIXME: Definite lists and maps
|
||||
public static final byte FALSE = -1, TRUE = -2;
|
||||
public static final byte INT8 = -3, INT16 = -4, INT32 = -5, INT64 = -6;
|
||||
public static final byte FLOAT32 = -7, FLOAT64 = -8;
|
||||
public static final byte UTF8 = -9, RAW = -10;
|
||||
public static final byte LIST_DEF = -11, MAP_DEF = -12;
|
||||
public static final byte LIST_INDEF = -13, MAP_INDEF = -14, END = -15;
|
||||
public static final byte NULL = -16;
|
||||
}
|
||||
32
api/net/sf/briar/api/serial/Writer.java
Normal file
32
api/net/sf/briar/api/serial/Writer.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface Writer {
|
||||
|
||||
void writeBoolean(boolean b) throws IOException;
|
||||
|
||||
void writeUint7(byte b) throws IOException;
|
||||
void writeInt8(byte b) throws IOException;
|
||||
void writeInt16(short s) throws IOException;
|
||||
void writeInt32(int i) throws IOException;
|
||||
void writeInt64(long l) throws IOException;
|
||||
void writeIntAny(long l) throws IOException;
|
||||
|
||||
void writeFloat32(float f) throws IOException;
|
||||
void writeFloat64(double d) throws IOException;
|
||||
|
||||
void writeUtf8(String s) throws IOException;
|
||||
void writeRaw(byte[] b) throws IOException;
|
||||
void writeRaw(Raw r) throws IOException;
|
||||
|
||||
void writeList(List<?> l, boolean definite) throws IOException;
|
||||
void writeList(List<?> l) throws IOException;
|
||||
|
||||
void writeMap(Map<?, ?> m, boolean definite) throws IOException;
|
||||
void writeMap(Map<?, ?> m) throws IOException;
|
||||
|
||||
void writeNull() throws IOException;
|
||||
}
|
||||
8
api/net/sf/briar/api/serial/WriterFactory.java
Normal file
8
api/net/sf/briar/api/serial/WriterFactory.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface WriterFactory {
|
||||
|
||||
Writer createWriter(OutputStream out);
|
||||
}
|
||||
@@ -7,14 +7,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.invitation.InvitationCallback;
|
||||
import net.sf.briar.api.invitation.InvitationParameters;
|
||||
import net.sf.briar.api.protocol.Transport.TransportDetails;
|
||||
import net.sf.briar.api.protocol.Transport.TransportDetails.TransportDetail;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
import net.sf.briar.util.FileUtils;
|
||||
|
||||
class InvitationWorker implements Runnable {
|
||||
@@ -22,13 +21,16 @@ class InvitationWorker implements Runnable {
|
||||
private final InvitationCallback callback;
|
||||
private final InvitationParameters parameters;
|
||||
private final DatabaseComponent databaseComponent;
|
||||
private final WriterFactory writerFactory;
|
||||
|
||||
InvitationWorker(final InvitationCallback callback,
|
||||
InvitationParameters parameters,
|
||||
DatabaseComponent databaseComponent) {
|
||||
DatabaseComponent databaseComponent,
|
||||
WriterFactory writerFactory) {
|
||||
this.callback = callback;
|
||||
this.parameters = parameters;
|
||||
this.databaseComponent = databaseComponent;
|
||||
this.writerFactory = writerFactory;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
@@ -65,6 +67,7 @@ class InvitationWorker implements Runnable {
|
||||
private File createInvitationDat(File dir) throws IOException {
|
||||
char[] password = parameters.getPassword();
|
||||
assert password != null;
|
||||
Arrays.fill(password, (char) 0);
|
||||
File invitationDat = new File(dir, "invitation.dat");
|
||||
callback.encryptingFile(invitationDat);
|
||||
// FIXME: Create a real invitation
|
||||
@@ -74,19 +77,11 @@ class InvitationWorker implements Runnable {
|
||||
} catch(DbException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
TransportDetails.Builder b = TransportDetails.newBuilder();
|
||||
for(Entry<String, String> e : transports.entrySet()) {
|
||||
TransportDetail.Builder b1 = TransportDetail.newBuilder();
|
||||
b1.setKey(e.getKey());
|
||||
b1.setValue(e.getValue());
|
||||
b.addDetails(b1.build());
|
||||
}
|
||||
TransportDetails t = b.build();
|
||||
FileOutputStream out = new FileOutputStream(invitationDat);
|
||||
t.writeTo(out);
|
||||
Writer w = writerFactory.createWriter(out);
|
||||
w.writeMap(transports);
|
||||
out.flush();
|
||||
out.close();
|
||||
Arrays.fill(password, (char) 0);
|
||||
return invitationDat;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,20 +4,25 @@ import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.invitation.InvitationCallback;
|
||||
import net.sf.briar.api.invitation.InvitationParameters;
|
||||
import net.sf.briar.api.invitation.InvitationWorkerFactory;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
class InvitationWorkerFactoryImpl implements InvitationWorkerFactory {
|
||||
|
||||
private final DatabaseComponent databaseComponent;
|
||||
private final WriterFactory writerFactory;
|
||||
|
||||
@Inject
|
||||
InvitationWorkerFactoryImpl(DatabaseComponent databaseComponent) {
|
||||
InvitationWorkerFactoryImpl(DatabaseComponent databaseComponent,
|
||||
WriterFactory writerFactory) {
|
||||
this.databaseComponent = databaseComponent;
|
||||
this.writerFactory = writerFactory;
|
||||
}
|
||||
|
||||
public Runnable createWorker(InvitationCallback callback,
|
||||
InvitationParameters parameters) {
|
||||
return new InvitationWorker(callback, parameters, databaseComponent);
|
||||
return new InvitationWorker(callback, parameters, databaseComponent,
|
||||
writerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
29
components/net/sf/briar/serial/RawImpl.java
Normal file
29
components/net/sf/briar/serial/RawImpl.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sf.briar.api.serial.Raw;
|
||||
|
||||
class RawImpl implements Raw {
|
||||
|
||||
private final byte[] bytes;
|
||||
|
||||
RawImpl(byte[] bytes) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof Raw) return Arrays.equals(bytes, ((Raw) o).getBytes());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
13
components/net/sf/briar/serial/ReaderFactoryImpl.java
Normal file
13
components/net/sf/briar/serial/ReaderFactoryImpl.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
import net.sf.briar.api.serial.ReaderFactory;
|
||||
|
||||
public class ReaderFactoryImpl implements ReaderFactory {
|
||||
|
||||
public Reader createReader(InputStream in) {
|
||||
return new ReaderImpl(in);
|
||||
}
|
||||
}
|
||||
360
components/net/sf/briar/serial/ReaderImpl.java
Normal file
360
components/net/sf/briar/serial/ReaderImpl.java
Normal file
@@ -0,0 +1,360 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.serial.FormatException;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
import net.sf.briar.api.serial.Tag;
|
||||
|
||||
public class ReaderImpl implements Reader {
|
||||
|
||||
private static final int TOO_LARGE_TO_KEEP = 4096;
|
||||
|
||||
private final InputStream in;
|
||||
private boolean started = false, eof = false;
|
||||
private byte next;
|
||||
private byte[] stringBuffer = null;
|
||||
|
||||
public ReaderImpl(InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
private byte readNext(boolean eofAcceptable) throws IOException {
|
||||
started = true;
|
||||
int i = in.read();
|
||||
if(i == -1) {
|
||||
eof = true;
|
||||
if(!eofAcceptable) throw new FormatException();
|
||||
}
|
||||
if(i > 127) i -= 256;
|
||||
next = (byte) i;
|
||||
return next;
|
||||
}
|
||||
|
||||
public boolean eof() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
return eof;
|
||||
}
|
||||
|
||||
public boolean hasBoolean() throws IOException {
|
||||
if(!started) readNext(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;
|
||||
}
|
||||
|
||||
public boolean hasUint7() throws IOException {
|
||||
if(!started) readNext(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;
|
||||
}
|
||||
|
||||
public boolean hasInt8() throws IOException {
|
||||
if(!started) readNext(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;
|
||||
}
|
||||
|
||||
public boolean hasInt16() throws IOException {
|
||||
if(!started) readNext(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;
|
||||
}
|
||||
|
||||
public boolean hasInt32() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.INT32;
|
||||
}
|
||||
|
||||
public int readInt32() throws IOException {
|
||||
if(!hasInt32()) throw new FormatException();
|
||||
return readInt32Bits();
|
||||
}
|
||||
|
||||
private int readInt32Bits() throws IOException {
|
||||
byte b1 = readNext(false);
|
||||
byte b2 = readNext(false);
|
||||
byte b3 = readNext(false);
|
||||
byte b4 = readNext(false);
|
||||
readNext(true);
|
||||
return ((b1 & 0xFF) << 24) | ((b2 & 0xFF) << 16) |
|
||||
((b3 & 0xFF) << 8) | (b4 & 0xFF);
|
||||
}
|
||||
|
||||
public boolean hasInt64() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.INT64;
|
||||
}
|
||||
|
||||
public long readInt64() throws IOException {
|
||||
if(!hasInt64()) throw new FormatException();
|
||||
return readInt64Bits();
|
||||
}
|
||||
|
||||
private long readInt64Bits() throws IOException {
|
||||
byte b1 = readNext(false);
|
||||
byte b2 = readNext(false);
|
||||
byte b3 = readNext(false);
|
||||
byte b4 = readNext(false);
|
||||
byte b5 = readNext(false);
|
||||
byte b6 = readNext(false);
|
||||
byte b7 = readNext(false);
|
||||
byte b8 = readNext(false);
|
||||
readNext(true);
|
||||
return ((b1 & 0xFFL) << 56) | ((b2 & 0xFFL) << 48) |
|
||||
((b3 & 0xFFL) << 40) | ((b4 & 0xFFL) << 32) |
|
||||
((b5 & 0xFFL) << 24) | ((b6 & 0xFFL) << 16) |
|
||||
((b7 & 0xFFL) << 8) | (b8 & 0xFFL);
|
||||
}
|
||||
|
||||
public boolean hasIntAny() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next >= 0 || next == Tag.INT8 || next == Tag.INT16
|
||||
|| next == Tag.INT32 || next == Tag.INT64;
|
||||
}
|
||||
|
||||
public long readIntAny() throws IOException {
|
||||
if(!hasIntAny()) 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();
|
||||
if(next == Tag.INT64) return readInt64();
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public boolean hasFloat32() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.FLOAT32;
|
||||
}
|
||||
|
||||
public float readFloat32() throws IOException {
|
||||
if(!hasFloat32()) throw new FormatException();
|
||||
return Float.intBitsToFloat(readInt32Bits());
|
||||
}
|
||||
|
||||
public boolean hasFloat64() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.FLOAT64;
|
||||
}
|
||||
|
||||
public double readFloat64() throws IOException {
|
||||
if(!hasFloat64()) throw new FormatException();
|
||||
return Double.longBitsToDouble(readInt64Bits());
|
||||
}
|
||||
|
||||
public boolean hasUtf8() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.UTF8;
|
||||
}
|
||||
|
||||
public String readUtf8() throws IOException {
|
||||
return readUtf8(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public String readUtf8(int maxLength) throws IOException {
|
||||
if(!hasUtf8()) throw new FormatException();
|
||||
readNext(false);
|
||||
long l = readIntAny();
|
||||
if(l < 0 || l > maxLength) throw new FormatException();
|
||||
int length = (int) l;
|
||||
if(length == 0) return "";
|
||||
if(stringBuffer == null || stringBuffer.length < length)
|
||||
stringBuffer = new byte[length];
|
||||
stringBuffer[0] = next;
|
||||
int offset = 1, read = 0;
|
||||
while(offset < length && read != -1) {
|
||||
read = in.read(stringBuffer, offset, length - offset);
|
||||
if(read != -1) offset += read;
|
||||
}
|
||||
if(offset < length) throw new FormatException();
|
||||
String s = new String(stringBuffer, 0, length, "UTF-8");
|
||||
if(length >= TOO_LARGE_TO_KEEP) stringBuffer = null;
|
||||
readNext(true);
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean hasRaw() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.RAW;
|
||||
}
|
||||
|
||||
public byte[] readRaw() throws IOException {
|
||||
return readRaw(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public byte[] readRaw(int maxLength) throws IOException {
|
||||
if(!hasRaw()) throw new FormatException();
|
||||
readNext(false);
|
||||
long l = readIntAny();
|
||||
if(l < 0 || l > maxLength) throw new FormatException();
|
||||
int length = (int) l;
|
||||
if(length == 0) return new byte[] {};
|
||||
byte[] b = new byte[length];
|
||||
b[0] = next;
|
||||
int offset = 1, read = 0;
|
||||
while(offset < length && read != -1) {
|
||||
read = in.read(b, offset, length - offset);
|
||||
if(read != -1) offset += read;
|
||||
}
|
||||
if(offset < length) throw new FormatException();
|
||||
readNext(true);
|
||||
return b;
|
||||
}
|
||||
|
||||
public boolean hasList(boolean definite) throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
if(definite) return next == Tag.LIST_DEF;
|
||||
else return next == Tag.LIST_INDEF;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public List<?> readList(boolean definite) throws IOException {
|
||||
if(!hasList(definite)) throw new FormatException();
|
||||
readNext(false);
|
||||
List list = new ArrayList();
|
||||
if(definite) {
|
||||
long l = readIntAny();
|
||||
if(l < 0 || l > Integer.MAX_VALUE) throw new FormatException();
|
||||
int length = (int) l;
|
||||
for(int i = 0; i < length; i++) list.add(readObject());
|
||||
} else {
|
||||
while(!hasEnd()) list.add(readObject());
|
||||
readEnd();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean hasEnd() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.END;
|
||||
}
|
||||
|
||||
private void readEnd() throws IOException {
|
||||
if(!hasEnd()) throw new FormatException();
|
||||
readNext(true);
|
||||
}
|
||||
|
||||
private Object readObject() throws IOException {
|
||||
if(!started) throw new IllegalStateException();
|
||||
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(hasUtf8()) return readUtf8();
|
||||
if(hasRaw()) return new RawImpl(readRaw());
|
||||
if(hasList()) return readList();
|
||||
if(hasMap()) return readMap();
|
||||
if(hasNull()) {
|
||||
readNull();
|
||||
return null;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public boolean hasList() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.LIST_DEF || next == Tag.LIST_INDEF;
|
||||
}
|
||||
|
||||
public List<?> readList() throws IOException {
|
||||
if(hasList(true)) return readList(true);
|
||||
if(hasList(false)) return readList(false);
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public boolean hasMap(boolean definite) throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
if(definite) return next == Tag.MAP_DEF;
|
||||
else return next == Tag.MAP_INDEF;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Map<?, ?> readMap(boolean definite) throws IOException {
|
||||
if(!hasMap(definite)) throw new FormatException();
|
||||
readNext(false);
|
||||
Map m = new HashMap();
|
||||
if(definite) {
|
||||
long l = readIntAny();
|
||||
if(l < 0 || l > Integer.MAX_VALUE) throw new FormatException();
|
||||
int length = (int) l;
|
||||
for(int i = 0; i < length; i++) m.put(readObject(), readObject());
|
||||
} else {
|
||||
while(!hasEnd()) m.put(readObject(), readObject());
|
||||
readEnd();
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public boolean hasMap() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.MAP_DEF || next == Tag.MAP_INDEF;
|
||||
}
|
||||
|
||||
public Map<?, ?> readMap() throws IOException {
|
||||
if(hasMap(true)) return readMap(true);
|
||||
if(hasMap(false)) return readMap(false);
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public boolean hasNull() throws IOException {
|
||||
if(!started) readNext(true);
|
||||
if(eof) return false;
|
||||
return next == Tag.NULL;
|
||||
}
|
||||
|
||||
public void readNull() throws IOException {
|
||||
if(!hasNull()) throw new FormatException();
|
||||
readNext(true);
|
||||
}
|
||||
}
|
||||
13
components/net/sf/briar/serial/WriterFactoryImpl.java
Normal file
13
components/net/sf/briar/serial/WriterFactoryImpl.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
public class WriterFactoryImpl implements WriterFactory {
|
||||
|
||||
public Writer createWriter(OutputStream out) {
|
||||
return new WriterImpl(out);
|
||||
}
|
||||
}
|
||||
166
components/net/sf/briar/serial/WriterImpl.java
Normal file
166
components/net/sf/briar/serial/WriterImpl.java
Normal file
@@ -0,0 +1,166 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.sf.briar.api.serial.Raw;
|
||||
import net.sf.briar.api.serial.Tag;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
public class WriterImpl implements Writer {
|
||||
|
||||
private final OutputStream out;
|
||||
|
||||
public WriterImpl(OutputStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public void writeBoolean(boolean b) throws IOException {
|
||||
if(b) out.write(Tag.TRUE);
|
||||
else out.write(Tag.FALSE);
|
||||
}
|
||||
|
||||
public void writeUint7(byte b) throws IOException {
|
||||
if(b < 0) throw new IllegalArgumentException();
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
public void writeInt8(byte b) throws IOException {
|
||||
out.write(Tag.INT8);
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
public void writeInt16(short s) throws IOException {
|
||||
out.write(Tag.INT16);
|
||||
out.write((byte) (s >> 8));
|
||||
out.write((byte) ((s << 8) >> 8));
|
||||
}
|
||||
|
||||
public void writeInt32(int i) throws IOException {
|
||||
out.write(Tag.INT32);
|
||||
writeInt32Bits(i);
|
||||
}
|
||||
|
||||
private void writeInt32Bits(int i) throws IOException {
|
||||
out.write((byte) (i >> 24));
|
||||
out.write((byte) ((i << 8) >> 24));
|
||||
out.write((byte) ((i << 16) >> 24));
|
||||
out.write((byte) ((i << 24) >> 24));
|
||||
}
|
||||
|
||||
public void writeInt64(long l) throws IOException {
|
||||
out.write(Tag.INT64);
|
||||
writeInt64Bits(l);
|
||||
}
|
||||
|
||||
private void writeInt64Bits(long l) throws IOException {
|
||||
out.write((byte) (l >> 56));
|
||||
out.write((byte) ((l << 8) >> 56));
|
||||
out.write((byte) ((l << 16) >> 56));
|
||||
out.write((byte) ((l << 24) >> 56));
|
||||
out.write((byte) ((l << 32) >> 56));
|
||||
out.write((byte) ((l << 40) >> 56));
|
||||
out.write((byte) ((l << 48) >> 56));
|
||||
out.write((byte) ((l << 56) >> 56));
|
||||
}
|
||||
|
||||
public void writeIntAny(long l) throws IOException {
|
||||
if(l >= 0 && l <= Byte.MAX_VALUE)
|
||||
writeUint7((byte) l);
|
||||
else if(l >= Byte.MIN_VALUE && l <= Byte.MAX_VALUE)
|
||||
writeInt8((byte) l);
|
||||
else if(l >= Short.MIN_VALUE && l <= Short.MAX_VALUE)
|
||||
writeInt16((short) l);
|
||||
else if(l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE)
|
||||
writeInt32((int) l);
|
||||
else writeInt64(l);
|
||||
}
|
||||
|
||||
public void writeFloat32(float f) throws IOException {
|
||||
out.write(Tag.FLOAT32);
|
||||
writeInt32Bits(Float.floatToRawIntBits(f));
|
||||
}
|
||||
|
||||
public void writeFloat64(double d) throws IOException {
|
||||
out.write(Tag.FLOAT64);
|
||||
writeInt64Bits(Double.doubleToRawLongBits(d));
|
||||
}
|
||||
|
||||
public void writeUtf8(String s) throws IOException {
|
||||
out.write(Tag.UTF8);
|
||||
byte[] b = s.getBytes("UTF-8");
|
||||
writeIntAny(b.length);
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
public void writeRaw(byte[] b) throws IOException {
|
||||
out.write(Tag.RAW);
|
||||
writeIntAny(b.length);
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
public void writeRaw(Raw r) throws IOException {
|
||||
writeRaw(r.getBytes());
|
||||
}
|
||||
|
||||
public void writeList(List<?> l, boolean definite) throws IOException {
|
||||
if(definite) {
|
||||
out.write(Tag.LIST_DEF);
|
||||
writeIntAny(l.size());
|
||||
for(Object o : l) writeObject(o);
|
||||
} else {
|
||||
out.write(Tag.LIST_INDEF);
|
||||
for(Object o : l) writeObject(o);
|
||||
out.write(Tag.END);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(Object o) throws IOException {
|
||||
if(o instanceof Boolean) writeBoolean((Boolean) o);
|
||||
else if(o instanceof Byte) writeIntAny((Byte) o);
|
||||
else if(o instanceof Short) writeIntAny((Short) o);
|
||||
else if(o instanceof Integer) writeIntAny((Integer) o);
|
||||
else if(o instanceof Long) writeIntAny((Long) o);
|
||||
else if(o instanceof Float) writeFloat32((Float) o);
|
||||
else if(o instanceof Double) writeFloat64((Double) o);
|
||||
else if(o instanceof String) writeUtf8((String) o);
|
||||
else if(o instanceof Raw) writeRaw((Raw) o);
|
||||
else if(o instanceof List) writeList((List<?>) o);
|
||||
else if(o instanceof Map) writeMap((Map<?, ?>) o);
|
||||
else if(o == null) writeNull();
|
||||
else throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public void writeList(List<?> l) throws IOException {
|
||||
writeList(l, true);
|
||||
}
|
||||
|
||||
public void writeMap(Map<?, ?> m, boolean definite) throws IOException {
|
||||
if(definite) {
|
||||
out.write(Tag.MAP_DEF);
|
||||
writeIntAny(m.size());
|
||||
for(Entry<?, ?> e : m.entrySet()) {
|
||||
writeObject(e.getKey());
|
||||
writeObject(e.getValue());
|
||||
}
|
||||
} else {
|
||||
out.write(Tag.MAP_INDEF);
|
||||
for(Entry<?, ?> e : m.entrySet()) {
|
||||
writeObject(e.getKey());
|
||||
writeObject(e.getValue());
|
||||
}
|
||||
out.write(Tag.END);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMap(Map<?, ?> m) throws IOException {
|
||||
writeMap(m, true);
|
||||
}
|
||||
|
||||
public void writeNull() throws IOException {
|
||||
out.write(Tag.NULL);
|
||||
}
|
||||
}
|
||||
BIN
lib/protobuf.jar
BIN
lib/protobuf.jar
Binary file not shown.
@@ -2,9 +2,11 @@ package net.sf.briar.invitation;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.TestUtils;
|
||||
@@ -12,6 +14,8 @@ import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.invitation.InvitationCallback;
|
||||
import net.sf.briar.api.invitation.InvitationParameters;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
@@ -38,13 +42,14 @@ public class InvitationWorkerTest extends TestCase {
|
||||
context.mock(InvitationParameters.class);
|
||||
final DatabaseComponent database =
|
||||
context.mock(DatabaseComponent.class);
|
||||
final WriterFactory writerFactory = context.mock(WriterFactory.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(params).getChosenLocation();
|
||||
will(returnValue(nonExistent));
|
||||
oneOf(callback).notFound(nonExistent);
|
||||
}});
|
||||
|
||||
new InvitationWorker(callback, params, database).run();
|
||||
new InvitationWorker(callback, params, database, writerFactory).run();
|
||||
|
||||
context.assertIsSatisfied();
|
||||
File[] children = testDir.listFiles();
|
||||
@@ -64,13 +69,14 @@ public class InvitationWorkerTest extends TestCase {
|
||||
context.mock(InvitationParameters.class);
|
||||
final DatabaseComponent database =
|
||||
context.mock(DatabaseComponent.class);
|
||||
final WriterFactory writerFactory = context.mock(WriterFactory.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(params).getChosenLocation();
|
||||
will(returnValue(exists));
|
||||
oneOf(callback).notDirectory(exists);
|
||||
}});
|
||||
|
||||
new InvitationWorker(callback, params, database).run();
|
||||
new InvitationWorker(callback, params, database, writerFactory).run();
|
||||
|
||||
context.assertIsSatisfied();
|
||||
File[] children = testDir.listFiles();
|
||||
@@ -101,6 +107,8 @@ public class InvitationWorkerTest extends TestCase {
|
||||
|
||||
private void testInstallerCreation(final boolean createExe,
|
||||
final boolean createJar) throws IOException, DbException {
|
||||
final Map<String, String> transports =
|
||||
Collections.singletonMap("foo", "bar");
|
||||
final File setup = new File(testDir, "setup.dat");
|
||||
TestUtils.createFile(setup, "foo bar baz");
|
||||
final File invitation = new File(testDir, "invitation.dat");
|
||||
@@ -121,6 +129,8 @@ public class InvitationWorkerTest extends TestCase {
|
||||
context.mock(InvitationParameters.class);
|
||||
final DatabaseComponent database =
|
||||
context.mock(DatabaseComponent.class);
|
||||
final WriterFactory writerFactory = context.mock(WriterFactory.class);
|
||||
final Writer writer = context.mock(Writer.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(params).getChosenLocation();
|
||||
will(returnValue(testDir));
|
||||
@@ -130,7 +140,10 @@ public class InvitationWorkerTest extends TestCase {
|
||||
will(returnValue(new char[] {'x', 'y', 'z', 'z', 'y'}));
|
||||
oneOf(callback).encryptingFile(invitation);
|
||||
oneOf(database).getTransports();
|
||||
will(returnValue(Collections.singletonMap("foo", "bar")));
|
||||
will(returnValue(transports));
|
||||
oneOf(writerFactory).createWriter(with(any(OutputStream.class)));
|
||||
will(returnValue(writer));
|
||||
oneOf(writer).writeMap(transports);
|
||||
oneOf(params).shouldCreateExe();
|
||||
will(returnValue(createExe));
|
||||
oneOf(params).shouldCreateJar();
|
||||
@@ -148,7 +161,7 @@ public class InvitationWorkerTest extends TestCase {
|
||||
oneOf(callback).created(expectedFiles);
|
||||
}});
|
||||
|
||||
new InvitationWorker(callback, params, database).run();
|
||||
new InvitationWorker(callback, params, database, writerFactory).run();
|
||||
|
||||
assertTrue(invitation.exists());
|
||||
assertEquals(createExe, exe.exists());
|
||||
|
||||
249
test/net/sf/briar/serial/ReaderImplTest.java
Normal file
249
test/net/sf/briar/serial/ReaderImplTest.java
Normal file
@@ -0,0 +1,249 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.api.serial.FormatException;
|
||||
import net.sf.briar.api.serial.Raw;
|
||||
import net.sf.briar.util.StringUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ReaderImplTest extends TestCase {
|
||||
|
||||
private ByteArrayInputStream in = null;
|
||||
private ReaderImpl r = null;
|
||||
|
||||
@Test
|
||||
public void testReadBoolean() throws IOException {
|
||||
setContents("FFFE");
|
||||
assertFalse(r.readBoolean());
|
||||
assertTrue(r.readBoolean());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInt8() throws IOException {
|
||||
setContents("FD00" + "FDFF" + "FD7F" + "FD80");
|
||||
assertEquals((byte) 0, r.readInt8());
|
||||
assertEquals((byte) -1, r.readInt8());
|
||||
assertEquals(Byte.MAX_VALUE, r.readInt8());
|
||||
assertEquals(Byte.MIN_VALUE, r.readInt8());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInt16() throws IOException {
|
||||
setContents("FC0000" + "FCFFFF" + "FC7FFF" + "FC8000");
|
||||
assertEquals((short) 0, r.readInt16());
|
||||
assertEquals((short) -1, r.readInt16());
|
||||
assertEquals(Short.MAX_VALUE, r.readInt16());
|
||||
assertEquals(Short.MIN_VALUE, r.readInt16());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInt32() throws IOException {
|
||||
setContents("FB00000000" + "FBFFFFFFFF" + "FB7FFFFFFF" + "FB80000000");
|
||||
assertEquals(0, r.readInt32());
|
||||
assertEquals(-1, r.readInt32());
|
||||
assertEquals(Integer.MAX_VALUE, r.readInt32());
|
||||
assertEquals(Integer.MIN_VALUE, r.readInt32());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInt64() throws IOException {
|
||||
setContents("FA0000000000000000" + "FAFFFFFFFFFFFFFFFF" +
|
||||
"FA7FFFFFFFFFFFFFFF" + "FA8000000000000000");
|
||||
assertEquals(0L, r.readInt64());
|
||||
assertEquals(-1L, r.readInt64());
|
||||
assertEquals(Long.MAX_VALUE, r.readInt64());
|
||||
assertEquals(Long.MIN_VALUE, r.readInt64());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadIntAny() throws IOException {
|
||||
setContents("00" + "7F" + "FD80" + "FDFF" + "FC0080" + "FC7FFF" +
|
||||
"FB00008000" + "FB7FFFFFFF" + "FA0000000080000000");
|
||||
assertEquals(0L, r.readIntAny());
|
||||
assertEquals(127L, r.readIntAny());
|
||||
assertEquals(-128L, r.readIntAny());
|
||||
assertEquals(-1L, r.readIntAny());
|
||||
assertEquals(128L, r.readIntAny());
|
||||
assertEquals(32767L, r.readIntAny());
|
||||
assertEquals(32768L, r.readIntAny());
|
||||
assertEquals(2147483647L, r.readIntAny());
|
||||
assertEquals(2147483648L, r.readIntAny());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadFloat32() throws IOException {
|
||||
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
|
||||
// http://steve.hollasch.net/cgindex/coding/ieeefloat.html
|
||||
setContents("F900000000" + "F93F800000" + "F940000000" + "F9BF800000" +
|
||||
"F980000000" + "F9FF800000" + "F97F800000" + "F97FC00000");
|
||||
assertEquals(0F, r.readFloat32());
|
||||
assertEquals(1F, r.readFloat32());
|
||||
assertEquals(2F, r.readFloat32());
|
||||
assertEquals(-1F, r.readFloat32());
|
||||
assertEquals(-0F, r.readFloat32());
|
||||
assertEquals(Float.NEGATIVE_INFINITY, r.readFloat32());
|
||||
assertEquals(Float.POSITIVE_INFINITY, r.readFloat32());
|
||||
assertTrue(Float.isNaN(r.readFloat32()));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadFloat64() throws IOException {
|
||||
setContents("F80000000000000000" + "F83FF0000000000000" +
|
||||
"F84000000000000000" + "F8BFF0000000000000" +
|
||||
"F88000000000000000" + "F8FFF0000000000000" +
|
||||
"F87FF0000000000000" + "F87FF8000000000000");
|
||||
assertEquals(0.0, r.readFloat64());
|
||||
assertEquals(1.0, r.readFloat64());
|
||||
assertEquals(2.0, r.readFloat64());
|
||||
assertEquals(-1.0, r.readFloat64());
|
||||
assertEquals(-0.0, r.readFloat64());
|
||||
assertEquals(Double.NEGATIVE_INFINITY, r.readFloat64());
|
||||
assertEquals(Double.POSITIVE_INFINITY, r.readFloat64());
|
||||
assertTrue(Double.isNaN(r.readFloat64()));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadUtf8() throws IOException {
|
||||
setContents("F703666F6F" + "F703666F6F" + "F700");
|
||||
assertEquals("foo", r.readUtf8());
|
||||
assertEquals("foo", r.readUtf8());
|
||||
assertEquals("", r.readUtf8());
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadUtf8MaxLengthNotExceeded() throws IOException {
|
||||
setContents("F703666F6F");
|
||||
assertEquals("foo", r.readUtf8(3));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadUtf8MaxLengthExceeded() throws IOException {
|
||||
setContents("F703666F6F");
|
||||
try {
|
||||
r.readUtf8(2);
|
||||
assertTrue(false);
|
||||
} catch(FormatException expected) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadRaw() throws IOException {
|
||||
setContents("F603010203" + "F603010203" + "F600");
|
||||
assertTrue(Arrays.equals(new byte[] {1, 2, 3}, r.readRaw()));
|
||||
assertTrue(Arrays.equals(new byte[] {1, 2, 3}, r.readRaw()));
|
||||
assertTrue(Arrays.equals(new byte[] {}, r.readRaw()));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadRawMaxLengthNotExceeded() throws IOException {
|
||||
setContents("F603010203");
|
||||
assertTrue(Arrays.equals(new byte[] {1, 2, 3}, r.readRaw(3)));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadRawMaxLengthExceeded() throws IOException {
|
||||
setContents("F603010203");
|
||||
try {
|
||||
r.readRaw(2);
|
||||
assertTrue(false);
|
||||
} catch(FormatException expected) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void testReadDefiniteList() throws IOException {
|
||||
setContents("F5" + "03" + "01" + "F703666F6F" + "FC0080");
|
||||
List l = r.readList(true);
|
||||
assertNotNull(l);
|
||||
assertEquals(3, l.size());
|
||||
assertEquals((byte) 1, l.get(0));
|
||||
assertEquals("foo", l.get(1));
|
||||
assertEquals((short) 128, l.get(2));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void testReadDefiniteMap() throws IOException {
|
||||
setContents("F4" + "02" + "F703666F6F" + "7B" + "F600" + "F0");
|
||||
Map m = r.readMap(true);
|
||||
assertNotNull(m);
|
||||
assertEquals(2, m.size());
|
||||
assertEquals((byte) 123, m.get("foo"));
|
||||
Raw raw = new RawImpl(new byte[] {});
|
||||
assertTrue(m.containsKey(raw));
|
||||
assertNull(m.get(raw));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void testReadIndefiniteList() throws IOException {
|
||||
setContents("F3" + "01" + "F703666F6F" + "FC0080" + "F1");
|
||||
List l = r.readList(false);
|
||||
assertNotNull(l);
|
||||
assertEquals(3, l.size());
|
||||
assertEquals((byte) 1, l.get(0));
|
||||
assertEquals("foo", l.get(1));
|
||||
assertEquals((short) 128, l.get(2));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void testReadIndefiniteMap() throws IOException {
|
||||
setContents("F2" + "F703666F6F" + "7B" + "F600" + "F0" + "F1");
|
||||
Map m = r.readMap(false);
|
||||
assertNotNull(m);
|
||||
assertEquals(2, m.size());
|
||||
assertEquals((byte) 123, m.get("foo"));
|
||||
Raw raw = new RawImpl(new byte[] {});
|
||||
assertTrue(m.containsKey(raw));
|
||||
assertNull(m.get(raw));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void testReadNestedMapsAndLists() throws IOException {
|
||||
setContents("F4" + "01" + "F4" + "01" + "F703666F6F" + "7B" +
|
||||
"F5" + "01" + "01");
|
||||
Map m = r.readMap();
|
||||
assertNotNull(m);
|
||||
assertEquals(1, m.size());
|
||||
Entry e = (Entry) m.entrySet().iterator().next();
|
||||
Map m1 = (Map) e.getKey();
|
||||
assertNotNull(m1);
|
||||
assertEquals(1, m1.size());
|
||||
assertEquals((byte) 123, m1.get("foo"));
|
||||
List l = (List) e.getValue();
|
||||
assertNotNull(l);
|
||||
assertEquals(1, l.size());
|
||||
assertEquals((byte) 1, l.get(0));
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
|
||||
private void setContents(String hex) {
|
||||
in = new ByteArrayInputStream(StringUtils.fromHexString(hex));
|
||||
r = new ReaderImpl(in);
|
||||
}
|
||||
}
|
||||
219
test/net/sf/briar/serial/WriterImplTest.java
Normal file
219
test/net/sf/briar/serial/WriterImplTest.java
Normal file
@@ -0,0 +1,219 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.util.StringUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class WriterImplTest extends TestCase {
|
||||
|
||||
private ByteArrayOutputStream out = null;
|
||||
private WriterImpl w = null;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
out = new ByteArrayOutputStream();
|
||||
w = new WriterImpl(out);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteBoolean() throws IOException {
|
||||
w.writeBoolean(true);
|
||||
w.writeBoolean(false);
|
||||
checkContents("FEFF");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteUint7() throws IOException {
|
||||
w.writeUint7((byte) 0);
|
||||
w.writeUint7((byte) 127);
|
||||
checkContents("00" + "7F");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteInt8() throws IOException {
|
||||
w.writeInt8((byte) 0);
|
||||
w.writeInt8((byte) -1);
|
||||
w.writeInt8((byte) -128);
|
||||
w.writeInt8((byte) 127);
|
||||
checkContents("FD00" + "FDFF" + "FD80" + "FD7F");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteInt16() throws IOException {
|
||||
w.writeInt16((short) 0);
|
||||
w.writeInt16((short) -1);
|
||||
w.writeInt16((short) -32768);
|
||||
w.writeInt16((short) 32767);
|
||||
checkContents("FC0000" + "FCFFFF" + "FC8000" + "FC7FFF");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteInt32() throws IOException {
|
||||
w.writeInt32(0);
|
||||
w.writeInt32(-1);
|
||||
w.writeInt32(-2147483648);
|
||||
w.writeInt32(2147483647);
|
||||
checkContents("FB00000000" + "FBFFFFFFFF" +
|
||||
"FB80000000" + "FB7FFFFFFF");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteInt64() throws IOException {
|
||||
w.writeInt64(0L);
|
||||
w.writeInt64(-1L);
|
||||
w.writeInt64(-9223372036854775808L);
|
||||
w.writeInt64(9223372036854775807L);
|
||||
checkContents("FA0000000000000000" + "FAFFFFFFFFFFFFFFFF" +
|
||||
"FA8000000000000000" + "FA7FFFFFFFFFFFFFFF");
|
||||
}
|
||||
|
||||
@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" +
|
||||
"FB00008000" + "FB7FFFFFFF" + "FA0000000080000000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteFloat32() throws IOException {
|
||||
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
|
||||
// 1 bit for sign, 8 for exponent, 23 for significand
|
||||
w.writeFloat32(0F); // 0 0 0 -> 0x00000000
|
||||
w.writeFloat32(1F); // 0 127 1 -> 0x3F800000
|
||||
w.writeFloat32(2F); // 0 128 1 -> 0x40000000
|
||||
w.writeFloat32(-1F); // 1 127 1 -> 0xBF800000
|
||||
w.writeFloat32(-0F); // 1 0 0 -> 0x80000000
|
||||
// http://steve.hollasch.net/cgindex/coding/ieeefloat.html
|
||||
w.writeFloat32(Float.NEGATIVE_INFINITY); // 1 255 0 -> 0xFF800000
|
||||
w.writeFloat32(Float.POSITIVE_INFINITY); // 0 255 0 -> 0x7F800000
|
||||
w.writeFloat32(Float.NaN); // 0 255 1 -> 0x7FC00000
|
||||
checkContents("F900000000" + "F93F800000" + "F940000000" +
|
||||
"F9BF800000" + "F980000000" + "F9FF800000" +
|
||||
"F97F800000" + "F97FC00000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteFloat64() throws IOException {
|
||||
// 1 bit for sign, 11 for exponent, 52 for significand
|
||||
w.writeFloat64(0.0); // 0 0 0 -> 0x0000000000000000
|
||||
w.writeFloat64(1.0); // 0 1023 1 -> 0x3FF0000000000000
|
||||
w.writeFloat64(2.0); // 0 1024 1 -> 0x4000000000000000
|
||||
w.writeFloat64(-1.0); // 1 1023 1 -> 0xBFF0000000000000
|
||||
w.writeFloat64(-0.0); // 1 0 0 -> 0x8000000000000000
|
||||
w.writeFloat64(Double.NEGATIVE_INFINITY); // 1 2047 0 -> 0xFFF00000...
|
||||
w.writeFloat64(Double.POSITIVE_INFINITY); // 0 2047 0 -> 0x7FF00000...
|
||||
w.writeFloat64(Double.NaN); // 0 2047 1 -> 0x7FF8000000000000
|
||||
checkContents("F80000000000000000" + "F83FF0000000000000" +
|
||||
"F84000000000000000" + "F8BFF0000000000000" +
|
||||
"F88000000000000000" + "F8FFF0000000000000" +
|
||||
"F87FF0000000000000" + "F87FF8000000000000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteUtf8() throws IOException {
|
||||
w.writeUtf8("foo");
|
||||
// UTF-8 tag, length as uint7, UTF-8 bytes
|
||||
checkContents("F7" + "03" + "666F6F");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteRawBytes() throws IOException {
|
||||
w.writeRaw(new byte[] {0, 1, -1, 127, -128});
|
||||
checkContents("F6" + "05" + "0001FF7F80");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteRawObject() throws IOException {
|
||||
w.writeRaw(new RawImpl(new byte[] {0, 1, -1, 127, -128}));
|
||||
checkContents("F6" + "05" + "0001FF7F80");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void testWriteDefiniteList() throws IOException {
|
||||
List l = new ArrayList();
|
||||
l.add(Byte.valueOf((byte) 1)); // Written as a uint7
|
||||
l.add("foo");
|
||||
l.add(Long.valueOf(128L)); // Written as an int16
|
||||
w.writeList(l, true);
|
||||
checkContents("F5" + "03" + "01" + "F703666F6F" + "FC0080");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void testWriteDefiniteMap() throws IOException {
|
||||
// Use LinkedHashMap to get predictable iteration order
|
||||
Map m = new LinkedHashMap();
|
||||
m.put("foo", Integer.valueOf(123)); // Written as a uint7
|
||||
m.put(new RawImpl(new byte[] {}), null); // Empty array != null
|
||||
w.writeMap(m, true);
|
||||
checkContents("F4" + "02" + "F703666F6F" + "7B" + "F600" + "F0");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void testWriteIndefiniteList() throws IOException {
|
||||
List l = new ArrayList();
|
||||
l.add(Byte.valueOf((byte) 1)); // Written as a uint7
|
||||
l.add("foo");
|
||||
l.add(Long.valueOf(128L)); // Written as an int16
|
||||
w.writeList(l, false);
|
||||
checkContents("F3" + "01" + "F703666F6F" + "FC0080" + "F1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void testWriteIndefiniteMap() throws IOException {
|
||||
// Use LinkedHashMap to get predictable iteration order
|
||||
Map m = new LinkedHashMap();
|
||||
m.put("foo", Integer.valueOf(123)); // Written as a uint7
|
||||
m.put(new RawImpl(new byte[] {}), null); // Empty array != null
|
||||
w.writeMap(m, false);
|
||||
checkContents("F2" + "F703666F6F" + "7B" + "F600" + "F0" + "F1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void testWriteNestedMapsAndLists() throws IOException {
|
||||
Map m = new LinkedHashMap();
|
||||
m.put("foo", Integer.valueOf(123));
|
||||
List l = new ArrayList();
|
||||
l.add(Byte.valueOf((byte) 1));
|
||||
Map m1 = new LinkedHashMap();
|
||||
m1.put(m, l);
|
||||
w.writeMap(m1);
|
||||
checkContents("F4" + "01" + "F4" + "01" + "F703666F6F" + "7B" +
|
||||
"F5" + "01" + "01");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteNull() throws IOException {
|
||||
w.writeNull();
|
||||
checkContents("F0");
|
||||
}
|
||||
|
||||
private void checkContents(String hex) throws IOException {
|
||||
out.flush();
|
||||
out.close();
|
||||
byte[] expected = StringUtils.fromHexString(hex);
|
||||
assertTrue(StringUtils.toHexString(out.toByteArray()),
|
||||
Arrays.equals(expected, out.toByteArray()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user