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.BDecodeMalformed;
|
||||
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 {
|
||||
private BValue root = null;
|
||||
|
|
@ -24,12 +25,23 @@ public class BTree {
|
|||
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);
|
||||
try {
|
||||
return Long.parseLong(strInt);
|
||||
} 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
|
||||
offset++;
|
||||
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 {
|
||||
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 {
|
||||
private static final long serialVersionUID = 8987586062482975916L;
|
||||
|
||||
public BDecodeParseError(byte[] data, int offset, Throwable cause) {
|
||||
super(data, offset, String.format("Failed to parse into primitive type at offset %d", offset));
|
||||
public BDecodeParseError(byte[] data, int offset, Throwable cause, String offense) {
|
||||
super(data, offset, String.format("Failed to parse into primitive type at offset %d: %s", offset, offense));
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class BTreeTest {
|
|||
|
||||
BValue root = tree.getRoot();
|
||||
assertNotNull(root);
|
||||
assertEquals(root, new BInteger(696969));
|
||||
assertEquals(new BInteger(696969), root);
|
||||
|
||||
System.out.println("testParseInt: " + root.toString());
|
||||
});
|
||||
|
|
@ -47,7 +47,7 @@ public class BTreeTest {
|
|||
|
||||
BValue root = tree.getRoot();
|
||||
assertNotNull(root);
|
||||
assertEquals(((BList)root).getLength(), 0);
|
||||
assertEquals(0, ((BList)root).getLength());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -70,16 +70,50 @@ public class BTreeTest {
|
|||
}
|
||||
}
|
||||
assertDoesNotThrow(() -> {
|
||||
assertEquals(list.get(BType.INTEGER, 0), new BInteger(1));
|
||||
assertEquals(list.get(BType.INTEGER, 1), new BInteger(2345678));
|
||||
assertEquals(new BInteger(1), list.get(BType.INTEGER, 0));
|
||||
assertEquals(new BInteger(2345678), list.get(BType.INTEGER, 1));
|
||||
|
||||
BInteger value = list
|
||||
.<BList>get(BType.LIST, 2)
|
||||
.<BInteger>get(BType.INTEGER, 0);
|
||||
assertNotNull(value);
|
||||
assertEquals(value, new BInteger(69));
|
||||
assertEquals(new BInteger(69), 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