diff --git a/briar-api/src/org/briarproject/api/data/BdfDictionary.java b/briar-api/src/org/briarproject/api/data/BdfDictionary.java new file mode 100644 index 0000000000000000000000000000000000000000..b37cfc606737a8dd8f0ba94a7f743cb09edb6e94 --- /dev/null +++ b/briar-api/src/org/briarproject/api/data/BdfDictionary.java @@ -0,0 +1,48 @@ +package org.briarproject.api.data; + +import java.util.Hashtable; + +public class BdfDictionary extends Hashtable<String, Object> { + + public Boolean getBoolean(String key, Boolean defaultValue) { + Object o = get(key); + if (o instanceof Boolean) return (Boolean) o; + return defaultValue; + } + + public Long getInteger(String key, Long defaultValue) { + Object o = get(key); + if (o instanceof Long) return (Long) o; + return defaultValue; + } + + public Double getFloat(String key, Double defaultValue) { + Object o = get(key); + if (o instanceof Double) return (Double) o; + return defaultValue; + } + + public String getString(String key, String defaultValue) { + Object o = get(key); + if (o instanceof String) return (String) o; + return defaultValue; + } + + public byte[] getRaw(String key, byte[] defaultValue) { + Object o = get(key); + if (o instanceof byte[]) return (byte[]) o; + return defaultValue; + } + + public BdfList getList(String key, BdfList defaultValue) { + Object o = get(key); + if (o instanceof BdfList) return (BdfList) o; + return defaultValue; + } + + public BdfDictionary getDictionary(String key, BdfDictionary defaultValue) { + Object o = get(key); + if (o instanceof BdfDictionary) return (BdfDictionary) o; + return defaultValue; + } +} diff --git a/briar-api/src/org/briarproject/api/data/BdfList.java b/briar-api/src/org/briarproject/api/data/BdfList.java new file mode 100644 index 0000000000000000000000000000000000000000..d39588d0d667e89f22018277a4a706930a27d181 --- /dev/null +++ b/briar-api/src/org/briarproject/api/data/BdfList.java @@ -0,0 +1,48 @@ +package org.briarproject.api.data; + +import java.util.Vector; + +public class BdfList extends Vector<Object> { + + public Boolean getBoolean(int index, Boolean defaultValue) { + Object o = get(index); + if (o instanceof Boolean) return (Boolean) o; + return defaultValue; + } + + public Long getInteger(int index, Long defaultValue) { + Object o = get(index); + if (o instanceof Long) return (Long) o; + return defaultValue; + } + + public Double getFloat(int index, Double defaultValue) { + Object o = get(index); + if (o instanceof Double) return (Double) o; + return defaultValue; + } + + public String getString(int index, String defaultValue) { + Object o = get(index); + if (o instanceof String) return (String) o; + return defaultValue; + } + + public byte[] getRaw(int index, byte[] defaultValue) { + Object o = get(index); + if (o instanceof byte[]) return (byte[]) o; + return defaultValue; + } + + public BdfList getList(int index, BdfList defaultValue) { + Object o = get(index); + if (o instanceof BdfList) return (BdfList) o; + return defaultValue; + } + + public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) { + Object o = get(index); + if (o instanceof BdfDictionary) return (BdfDictionary) o; + return defaultValue; + } +} diff --git a/briar-api/src/org/briarproject/api/data/MetadataParser.java b/briar-api/src/org/briarproject/api/data/MetadataParser.java new file mode 100644 index 0000000000000000000000000000000000000000..798ad5df9c4a21067214e5d2d71fb98340be7455 --- /dev/null +++ b/briar-api/src/org/briarproject/api/data/MetadataParser.java @@ -0,0 +1,9 @@ +package org.briarproject.api.data; + +import org.briarproject.api.FormatException; +import org.briarproject.api.db.Metadata; + +public interface MetadataParser { + + BdfDictionary parse(Metadata m) throws FormatException; +} diff --git a/briar-api/src/org/briarproject/api/db/Metadata.java b/briar-api/src/org/briarproject/api/db/Metadata.java new file mode 100644 index 0000000000000000000000000000000000000000..c54d15cff74f2504e77bf52d64c9c02c934ea7e7 --- /dev/null +++ b/briar-api/src/org/briarproject/api/db/Metadata.java @@ -0,0 +1,6 @@ +package org.briarproject.api.db; + +import java.util.Hashtable; + +public class Metadata extends Hashtable<String, byte[]> { +} diff --git a/briar-core/src/org/briarproject/data/DataModule.java b/briar-core/src/org/briarproject/data/DataModule.java index c532b833b14d7a94338a90ecbef14ac16646a177..85d7b311a0cfc508a9b215a6b651d848202615f7 100644 --- a/briar-core/src/org/briarproject/data/DataModule.java +++ b/briar-core/src/org/briarproject/data/DataModule.java @@ -4,6 +4,7 @@ import com.google.inject.AbstractModule; import org.briarproject.api.data.BdfReaderFactory; import org.briarproject.api.data.BdfWriterFactory; +import org.briarproject.api.data.MetadataParser; public class DataModule extends AbstractModule { @@ -11,5 +12,6 @@ public class DataModule extends AbstractModule { protected void configure() { bind(BdfReaderFactory.class).to(BdfReaderFactoryImpl.class); bind(BdfWriterFactory.class).to(BdfWriterFactoryImpl.class); + bind(MetadataParser.class).to(MetadataParserImpl.class); } } diff --git a/briar-core/src/org/briarproject/data/MetadataParserImpl.java b/briar-core/src/org/briarproject/data/MetadataParserImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..954838072c98c90489f3eb6ee088a00df70031ab --- /dev/null +++ b/briar-core/src/org/briarproject/data/MetadataParserImpl.java @@ -0,0 +1,168 @@ +package org.briarproject.data; + +import org.briarproject.api.FormatException; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataParser; +import org.briarproject.api.db.Metadata; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.util.Map; + +import static org.briarproject.data.Types.DICTIONARY; +import static org.briarproject.data.Types.END; +import static org.briarproject.data.Types.FALSE; +import static org.briarproject.data.Types.FLOAT_64; +import static org.briarproject.data.Types.INT_16; +import static org.briarproject.data.Types.INT_32; +import static org.briarproject.data.Types.INT_64; +import static org.briarproject.data.Types.INT_8; +import static org.briarproject.data.Types.LIST; +import static org.briarproject.data.Types.NULL; +import static org.briarproject.data.Types.RAW_16; +import static org.briarproject.data.Types.RAW_32; +import static org.briarproject.data.Types.RAW_8; +import static org.briarproject.data.Types.STRING_16; +import static org.briarproject.data.Types.STRING_32; +import static org.briarproject.data.Types.STRING_8; +import static org.briarproject.data.Types.TRUE; + +class MetadataParserImpl implements MetadataParser { + + @Override + public BdfDictionary parse(Metadata m) throws FormatException { + BdfDictionary dict = new BdfDictionary(); + for (Map.Entry<String, byte[]> e : m.entrySet()) + dict.put(e.getKey(), parseObject(e.getValue())); + return dict; + } + + private Object parseObject(byte[] b) throws FormatException { + if (b == null) return null; + ByteArrayInputStream in = new ByteArrayInputStream(b); + Object o = parseObject(in); + if (in.available() > 0) throw new FormatException(); + return o; + } + + private Object parseObject(ByteArrayInputStream in) throws FormatException { + switch(in.read()) { + case NULL: + return null; + case TRUE: + return Boolean.TRUE; + case FALSE: + return Boolean.FALSE; + case INT_8: + return (long) parseInt8(in); + case INT_16: + return (long) parseInt16(in); + case INT_32: + return (long) parseInt32(in); + case INT_64: + return parseInt64(in); + case FLOAT_64: + return Double.longBitsToDouble(parseInt64(in)); + case STRING_8: + return parseString(in, parseInt8(in)); + case STRING_16: + return parseString(in, parseInt16(in)); + case STRING_32: + return parseString(in, parseInt32(in)); + case RAW_8: + return parseRaw(in, parseInt8(in)); + case RAW_16: + return parseRaw(in, parseInt16(in)); + case RAW_32: + return parseRaw(in, parseInt32(in)); + case LIST: + return parseList(in); + case DICTIONARY: + return parseDictionary(in); + default: + throw new FormatException(); + } + } + + private String parseString(ByteArrayInputStream in) throws FormatException { + switch(in.read()) { + case STRING_8: + return parseString(in, parseInt8(in)); + case STRING_16: + return parseString(in, parseInt16(in)); + case STRING_32: + return parseString(in, parseInt32(in)); + default: + throw new FormatException(); + } + } + + private byte parseInt8(ByteArrayInputStream in) throws FormatException { + if (in.available() < 1) throw new FormatException(); + return (byte) in.read(); + } + + private short parseInt16(ByteArrayInputStream in) throws FormatException { + if (in.available() < 2) throw new FormatException(); + return (short) (((in.read() & 0xFF) << 8) + (in.read() & 0xFF)); + } + + private int parseInt32(ByteArrayInputStream in) throws FormatException { + if (in.available() < 4) throw new FormatException(); + int value = 0; + for (int i = 0; i < 4; i++) + value |= (in.read() & 0xFF) << (24 - i * 8); + return value; + } + + private long parseInt64(ByteArrayInputStream in) throws FormatException { + if (in.available() < 8) throw new FormatException(); + long value = 0; + for (int i = 0; i < 8; i++) + value |= (in.read() & 0xFFL) << (56 - i * 8); + return value; + } + + private String parseString(ByteArrayInputStream in, int len) + throws FormatException { + if (len < 0) throw new FormatException(); + byte[] b = new byte[len]; + if (in.read(b, 0, len) != len) throw new FormatException(); + try { + return new String(b, 0, len, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(); + } + } + + private byte[] parseRaw(ByteArrayInputStream in, int len) + throws FormatException { + if (len < 0) throw new FormatException(); + byte[] b = new byte[len]; + if (in.read(b, 0, len) != len) throw new FormatException(); + return b; + } + + private BdfList parseList(ByteArrayInputStream in) throws FormatException { + BdfList list = new BdfList(); + while (peek(in) != END) list.add(parseObject(in)); + if (in.read() != END) throw new FormatException(); + return list; + } + + private BdfDictionary parseDictionary(ByteArrayInputStream in) + throws FormatException { + BdfDictionary dict = new BdfDictionary(); + while (peek(in) != END) dict.put(parseString(in), parseObject(in)); + if (in.read() != END) throw new FormatException(); + return dict; + } + + private int peek(ByteArrayInputStream in) { + in.mark(1); + int next = in.read(); + in.reset(); + return next; + } +}