full bencode decoding is done now, later may need even more tests
This commit is contained in:
parent
f5ab05acdc
commit
c1dcb19f9d
3 changed files with 100 additions and 12 deletions
|
|
@ -6,7 +6,8 @@ import java.util.Arrays;
|
||||||
import com.mykola2312.retracker.bencode.error.BDecodeError;
|
import com.mykola2312.retracker.bencode.error.BDecodeError;
|
||||||
import com.mykola2312.retracker.bencode.error.BDecodeMalformed;
|
import com.mykola2312.retracker.bencode.error.BDecodeMalformed;
|
||||||
import com.mykola2312.retracker.bencode.error.BDecodeParseError;
|
import com.mykola2312.retracker.bencode.error.BDecodeParseError;
|
||||||
import com.mykola2312.retracker.bencode.error.BDecodeUnknown;
|
import com.mykola2312.retracker.bencode.error.BErrorNoRoot;
|
||||||
|
import com.mykola2312.retracker.bencode.error.BErrorValueCast;
|
||||||
|
|
||||||
public class BTree {
|
public class BTree {
|
||||||
private BValue root = null;
|
private BValue root = null;
|
||||||
|
|
@ -24,12 +25,23 @@ public class BTree {
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long parseLong(byte[] bytes) throws BDecodeParseError {
|
// used to parse string lengths
|
||||||
|
private int parseInt(byte[] bytes) throws BDecodeParseError {
|
||||||
|
String strInt = new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(strInt);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new BDecodeParseError(data, offset, e, strInt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for BInteger
|
||||||
|
private long parseLong(byte[] bytes) throws BDecodeParseError {
|
||||||
String strInt = new String(bytes, StandardCharsets.UTF_8);
|
String strInt = new String(bytes, StandardCharsets.UTF_8);
|
||||||
try {
|
try {
|
||||||
return Long.parseLong(strInt);
|
return Long.parseLong(strInt);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new BDecodeParseError(data, offset, e);
|
throw new BDecodeParseError(data, offset, e, strInt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,13 +87,55 @@ public class BTree {
|
||||||
// advance past terminator
|
// advance past terminator
|
||||||
offset++;
|
offset++;
|
||||||
return list;
|
return list;
|
||||||
|
} else if (type == BDecoder.BE_DICT) {
|
||||||
|
BDict dict = new BDict();
|
||||||
|
// same business as BList, but we read pairs of values, key and value
|
||||||
|
while (offset < data.length && data[offset] != BDecoder.BE_END) {
|
||||||
|
BValue key = decode();
|
||||||
|
BValue value = decode();
|
||||||
|
dict.set(key, value);
|
||||||
|
}
|
||||||
|
// advance past terminator
|
||||||
|
offset++;
|
||||||
|
return dict;
|
||||||
|
} else { // string
|
||||||
|
// since string does not have leading type byte, move back offset
|
||||||
|
offset--;
|
||||||
|
// find string separator
|
||||||
|
int sep = offset;
|
||||||
|
while (sep < data.length && data[sep] != BDecoder.BE_STRING_SEP) {
|
||||||
|
sep++;
|
||||||
|
}
|
||||||
|
if (sep == data.length) {
|
||||||
|
throw new BDecodeMalformed(data, offset, "no string separator");
|
||||||
|
}
|
||||||
|
// everything before sep is integer of string length
|
||||||
|
int length = parseInt(Arrays.copyOfRange(data, offset, sep));
|
||||||
|
if (offset + length >= data.length) {
|
||||||
|
throw new BDecodeMalformed(data, offset, "string length is bigger than data");
|
||||||
|
}
|
||||||
|
|
||||||
|
BString string = new BString(Arrays.copyOfRange(data, sep + 1, sep + 1 + length));
|
||||||
|
offset = sep + 1 + length;
|
||||||
|
|
||||||
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new BDecodeUnknown(data, offset, type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decode(byte[] data) throws BDecodeError {
|
public void decode(byte[] data) throws BDecodeError {
|
||||||
this.root = new BDecoder(data, 0).decode();
|
this.root = new BDecoder(data, 0).decode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BDict asDict() throws BErrorNoRoot, BErrorValueCast {
|
||||||
|
if (root == null) {
|
||||||
|
throw new BErrorNoRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!root.getType().equals(BType.DICT)) {
|
||||||
|
throw new BErrorValueCast(root, "", BType.DICT, root.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (BDict)root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package com.mykola2312.retracker.bencode.error;
|
||||||
public class BDecodeParseError extends BDecodeError {
|
public class BDecodeParseError extends BDecodeError {
|
||||||
private static final long serialVersionUID = 8987586062482975916L;
|
private static final long serialVersionUID = 8987586062482975916L;
|
||||||
|
|
||||||
public BDecodeParseError(byte[] data, int offset, Throwable cause) {
|
public BDecodeParseError(byte[] data, int offset, Throwable cause, String offense) {
|
||||||
super(data, offset, String.format("Failed to parse into primitive type at offset %d", offset));
|
super(data, offset, String.format("Failed to parse into primitive type at offset %d: %s", offset, offense));
|
||||||
initCause(cause);
|
initCause(cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public class BTreeTest {
|
||||||
|
|
||||||
BValue root = tree.getRoot();
|
BValue root = tree.getRoot();
|
||||||
assertNotNull(root);
|
assertNotNull(root);
|
||||||
assertEquals(root, new BInteger(696969));
|
assertEquals(new BInteger(696969), root);
|
||||||
|
|
||||||
System.out.println("testParseInt: " + root.toString());
|
System.out.println("testParseInt: " + root.toString());
|
||||||
});
|
});
|
||||||
|
|
@ -47,7 +47,7 @@ public class BTreeTest {
|
||||||
|
|
||||||
BValue root = tree.getRoot();
|
BValue root = tree.getRoot();
|
||||||
assertNotNull(root);
|
assertNotNull(root);
|
||||||
assertEquals(((BList)root).getLength(), 0);
|
assertEquals(0, ((BList)root).getLength());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,16 +70,50 @@ public class BTreeTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertDoesNotThrow(() -> {
|
assertDoesNotThrow(() -> {
|
||||||
assertEquals(list.get(BType.INTEGER, 0), new BInteger(1));
|
assertEquals(new BInteger(1), list.get(BType.INTEGER, 0));
|
||||||
assertEquals(list.get(BType.INTEGER, 1), new BInteger(2345678));
|
assertEquals(new BInteger(2345678), list.get(BType.INTEGER, 1));
|
||||||
|
|
||||||
BInteger value = list
|
BInteger value = list
|
||||||
.<BList>get(BType.LIST, 2)
|
.<BList>get(BType.LIST, 2)
|
||||||
.<BInteger>get(BType.INTEGER, 0);
|
.<BInteger>get(BType.INTEGER, 0);
|
||||||
assertNotNull(value);
|
assertNotNull(value);
|
||||||
assertEquals(value, new BInteger(69));
|
assertEquals(new BInteger(69), value);
|
||||||
System.out.println("value from nested list: " + value);
|
System.out.println("value from nested list: " + value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testString() throws BDecodeError {
|
||||||
|
final byte[] data = "11:testString!".getBytes();
|
||||||
|
|
||||||
|
BTree tree = new BTree();
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
tree.decode(data);
|
||||||
|
|
||||||
|
assertNotNull(tree.getRoot());
|
||||||
|
|
||||||
|
BString string = (BString)tree.getRoot();
|
||||||
|
System.out.println("string: " + string);
|
||||||
|
assertEquals(new BString("testString!"), string);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDict() throws BDecodeError {
|
||||||
|
final byte[] data = "di0e5:first6:secondi69ee".getBytes();
|
||||||
|
|
||||||
|
BTree tree = new BTree();
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
tree.decode(data);
|
||||||
|
|
||||||
|
BDict root = tree.asDict();
|
||||||
|
// check keys
|
||||||
|
assertEquals(new BInteger(0), root.find(new BInteger(0)));
|
||||||
|
assertEquals(new BString("second"), root.find(new BString("second")));
|
||||||
|
// check values
|
||||||
|
assertEquals(new BString("first"), root.get(new BInteger(0)));
|
||||||
|
assertEquals(new BInteger(69), root.<BInteger>get(BType.INTEGER, "second"));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue