diff --git a/src/main/java/com/mykola2312/retracker/bencode/BDict.java b/src/main/java/com/mykola2312/retracker/bencode/BDict.java index a0b9a09..1f1d17d 100644 --- a/src/main/java/com/mykola2312/retracker/bencode/BDict.java +++ b/src/main/java/com/mykola2312/retracker/bencode/BDict.java @@ -1,5 +1,6 @@ package com.mykola2312.retracker.bencode; +import com.mykola2312.retracker.bencode.error.BErrorInvalidKey; import com.mykola2312.retracker.bencode.error.BErrorKeyNotFound; import com.mykola2312.retracker.bencode.error.BErrorNoChildren; import com.mykola2312.retracker.bencode.error.BErrorValueCast; @@ -11,7 +12,20 @@ public class BDict extends BList { return BType.DICT; } - public BDict set(BValue key, BValue value) { + public BDict set(BValue key, BValue value) throws BErrorInvalidKey { + if (key == null || value == null) { + throw new BErrorInvalidKey(this, key, "key or value is null"); + } + /* key type cannot have child, because it messes up tree, + * in other words, key cannot be a list or dict + */ + if (key.getChild() != null) { + throw new BErrorInvalidKey(this, key, "key has child, because its list or a dict"); + } + if (key.getType().equals(BType.LIST) || key.getType().equals(BType.DICT)) { + throw new BErrorInvalidKey(this, key, "key shall not be list or a dict"); + } + BValue node = find(key); if (node != null) { node.setNext(value); @@ -24,7 +38,14 @@ public class BDict extends BList { } public BDict set(String key, BValue value) { - return set(new BString(key), value); + /* we "suppress" here exceptions since this method is used + * for building BTrees, not when decoding + */ + try { + return set(new BString(key), value); + } catch (BErrorInvalidKey e) { + throw new RuntimeException("this shouldn't have happened in BDict set: " + e.getMessage()); + } } /* since we're going to employ builder pattern, we can't return null. diff --git a/src/main/java/com/mykola2312/retracker/bencode/BTree.java b/src/main/java/com/mykola2312/retracker/bencode/BTree.java index 7f46e69..0e8337b 100644 --- a/src/main/java/com/mykola2312/retracker/bencode/BTree.java +++ b/src/main/java/com/mykola2312/retracker/bencode/BTree.java @@ -1,12 +1,14 @@ package com.mykola2312.retracker.bencode; import static io.netty.buffer.Unpooled.buffer; + import java.nio.charset.StandardCharsets; 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.BErrorInvalidKey; import com.mykola2312.retracker.bencode.error.BErrorNoRoot; import com.mykola2312.retracker.bencode.error.BErrorValueCast; @@ -102,7 +104,11 @@ public class BTree { while (offset < data.length && data[offset] != BTree.BE_END) { BValue key = decode(); BValue value = decode(); - dict.set(key, value); + try { + dict.set(key, value); + } catch (BErrorInvalidKey e) { + throw new BDecodeMalformed(data, offset, e.getMessage()); + } } // advance past terminator offset++; @@ -171,6 +177,7 @@ public class BTree { case LIST: buffer.writeByte(BE_LIST); for (BValue item : node) { + System.err.println("encoding list item: " + item); encode(item); } buffer.writeByte(BE_END); diff --git a/src/main/java/com/mykola2312/retracker/bencode/error/BErrorInvalidKey.java b/src/main/java/com/mykola2312/retracker/bencode/error/BErrorInvalidKey.java new file mode 100644 index 0000000..102b3c1 --- /dev/null +++ b/src/main/java/com/mykola2312/retracker/bencode/error/BErrorInvalidKey.java @@ -0,0 +1,11 @@ +package com.mykola2312.retracker.bencode.error; + +import com.mykola2312.retracker.bencode.BValue; + +public class BErrorInvalidKey extends BValueError { + private static final long serialVersionUID = 8821935501326704941L; + + public BErrorInvalidKey(BValue node, BValue key, String message) { + super(node, String.format("key \"%s\" invalid: %s", key, message)); + } +} diff --git a/src/test/java/com/mykola2312/retracker/bencode/BDictTest.java b/src/test/java/com/mykola2312/retracker/bencode/BDictTest.java index 7898faa..4773807 100644 --- a/src/test/java/com/mykola2312/retracker/bencode/BDictTest.java +++ b/src/test/java/com/mykola2312/retracker/bencode/BDictTest.java @@ -8,6 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import org.junit.jupiter.api.Test; +import com.mykola2312.retracker.bencode.error.BErrorInvalidKey; import com.mykola2312.retracker.bencode.error.BErrorKeyNotFound; import com.mykola2312.retracker.bencode.error.BErrorValueCast; import com.mykola2312.retracker.bencode.error.BValueError; @@ -37,7 +38,7 @@ public class BDictTest { } @Test - public void testKeyChild() { + public void testKeyChild() throws BErrorInvalidKey { BDict dict = new BDict(); dict.set(new BInteger(1), new BInteger(2)); diff --git a/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java b/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java index fea0e54..f63333b 100644 --- a/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java +++ b/src/test/java/com/mykola2312/retracker/bencode/BTreeTest.java @@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -15,6 +16,7 @@ import org.junit.jupiter.api.Test; import com.mykola2312.retracker.bencode.error.BDecodeError; import com.mykola2312.retracker.bencode.error.BDecodeMalformed; import com.mykola2312.retracker.bencode.error.BError; +import com.mykola2312.retracker.bencode.error.BErrorInvalidKey; public class BTreeTest { @Test @@ -141,6 +143,17 @@ public class BTreeTest { }); } + @Test + public void testInvalidKeys() { + assertThrows(BErrorInvalidKey.class, () -> { + new BTree().setRoot(new BDict()).set(new BList(), new BList()); + }); + + assertThrows(BDecodeMalformed.class, () -> { + new BTree().decode("dlelee".getBytes()); + }); + } + @Test public void testEncode() { assertDoesNotThrow(() -> { @@ -148,6 +161,9 @@ public class BTreeTest { tree.setRoot(new BInteger(1)); assertArrayEquals("i1e".getBytes(), tree.encode()); + + tree.setRoot(new BString("test")); + assertArrayEquals("4:test".getBytes(), tree.encode()); }); }