From 24e9568f89cedc2705f61b9503fc95c8e4a1803e Mon Sep 17 00:00:00 2001 From: mykola2312 <49044616+mykola2312@users.noreply.github.com> Date: Tue, 15 Oct 2024 04:06:26 +0300 Subject: [PATCH] implement BList decoding, fix numerous bugs in BList --- .../mykola2312/retracker/bencode/BList.java | 6 +++ .../mykola2312/retracker/bencode/BTree.java | 29 +++++++----- .../bencode/error/BDecodeUnknown.java | 2 +- .../retracker/bencode/BTreeTest.java | 46 +++++++++++++++++++ 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/mykola2312/retracker/bencode/BList.java b/src/main/java/com/mykola2312/retracker/bencode/BList.java index 51cf97b..6fd5449 100644 --- a/src/main/java/com/mykola2312/retracker/bencode/BList.java +++ b/src/main/java/com/mykola2312/retracker/bencode/BList.java @@ -36,6 +36,12 @@ public class BList extends BValue { // builder public BList append(BValue item) { + // do not allow any nulls pass into list, because it fucks up everything + if (item == null) { + // fail earlier than fail horribly + throw new NullPointerException(); + } + BValue first = getFirst(); BValue last = getLast(); if (first == null) { diff --git a/src/main/java/com/mykola2312/retracker/bencode/BTree.java b/src/main/java/com/mykola2312/retracker/bencode/BTree.java index 3c24728..d24b544 100644 --- a/src/main/java/com/mykola2312/retracker/bencode/BTree.java +++ b/src/main/java/com/mykola2312/retracker/bencode/BTree.java @@ -6,6 +6,7 @@ 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; public class BTree { private BValue root = null; @@ -39,8 +40,7 @@ public class BTree { private static final byte BE_END = (byte)'e'; public BValue decode() throws BDecodeError { - BType type; - if (data.length < 2) { + if (data.length - offset < 2) { /* no bencode data can be less than 2 bytes: for integer must be 'i0e' atleast, * strings must be at least '0:' and lists and dicts can be empty */ @@ -48,15 +48,9 @@ public class BTree { } // consume and determine type - switch (data[offset]) { - case BE_INTEGER: type = BType.INTEGER; break; - case BE_LIST: type = BType.LIST; break; - case BE_DICT: type = BType.DICT; break; - default: type = BType.STRING; - } - offset++; + byte type = data[offset++]; - if (type.equals(BType.INTEGER)) { + if (type == BDecoder.BE_INTEGER) { // advance until we hit end marker int end = offset; while (end < data.length && data[end] != BDecoder.BE_END) { @@ -67,10 +61,23 @@ public class BTree { } // convert bytes to string and string to integer byte[] bytes = Arrays.copyOfRange(data, offset, end); + // after parsing integer set new offset and advance past terminator + offset = end + 1; + return new BInteger(parseLong(bytes)); + } else if (type == BDecoder.BE_LIST) { + BList list = new BList(); + // we're going to use recursion to read elements until we hit end + while (offset < data.length && data[offset] != BDecoder.BE_END) { + BValue item = decode(); + list.append(item); + } + // advance past terminator + offset++; + return list; } - return null; + throw new BDecodeUnknown(data, offset, type); } } diff --git a/src/main/java/com/mykola2312/retracker/bencode/error/BDecodeUnknown.java b/src/main/java/com/mykola2312/retracker/bencode/error/BDecodeUnknown.java index 6deb59d..8ece978 100644 --- a/src/main/java/com/mykola2312/retracker/bencode/error/BDecodeUnknown.java +++ b/src/main/java/com/mykola2312/retracker/bencode/error/BDecodeUnknown.java @@ -6,7 +6,7 @@ public class BDecodeUnknown extends BDecodeError { byte unknown; public BDecodeUnknown(byte[] data, int offset, byte unknown) { - super(data, offset, String.format("Unknown symbol 0x%x at offset %d", unknown)); + super(data, offset, String.format("Unknown symbol 0x%x at offset %d", unknown, offset)); this.unknown = unknown; } } diff --git a/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java b/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java index 7c7abf8..3914595 100644 --- a/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java +++ b/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java @@ -36,4 +36,50 @@ public class BTreeTest { tree.decode(data); }); } + + @Test + public void testEmptyList() throws BDecodeError { + final byte[] data = "le".getBytes(); + + BTree tree = new BTree(); + assertDoesNotThrow(() -> { + tree.decode(data); + + BValue root = tree.getRoot(); + assertNotNull(root); + assertEquals(((BList)root).getLength(), 0); + }); + } + + @Test + public void testList() throws BDecodeError { + final byte[] data = "li1ei2345678eli69eee".getBytes(); + + BTree tree = new BTree(); + assertDoesNotThrow(() -> { + tree.decode(data); + + assertNotNull(tree.getRoot()); + + BList list = (BList)tree.getRoot(); + { + System.out.println(String.format("BDecode'd list size: %d", list.getLength())); + System.out.println("BDecode'd list contents:"); + for (BValue item : list) { + System.out.println(item.toString()); + } + } + assertDoesNotThrow(() -> { + assertEquals(list.get(BType.INTEGER, 0), new BInteger(1)); + assertEquals(list.get(BType.INTEGER, 1), new BInteger(2345678)); + + BInteger value = list + .get(BType.LIST, 2) + .get(BType.INTEGER, 0); + assertNotNull(value); + assertEquals(value, new BInteger(69)); + System.out.println("value from nested list: " + value); + }); + }); + } }