From 8994bcf2097f5e2d389a696de8563e33059dcfba Mon Sep 17 00:00:00 2001 From: TheEntropyShard Date: Wed, 1 Feb 2023 19:17:36 +0300 Subject: [PATCH] Fully fixed decoding, added Test.java and Shell build script --- build.sh | 9 + resources/readme.txt | 4 +- resources/test_data.txt | 101 ++++++++ src/me/theentropyshard/jdarkroom/Decoder.java | 28 +-- .../jdarkroom/DecodingData.java | 218 ++++++++++++------ src/me/theentropyshard/jdarkroom/I18N.java | 4 +- src/me/theentropyshard/jdarkroom/Utils.java | 6 + test/Test.java | 23 ++ 8 files changed, 305 insertions(+), 88 deletions(-) create mode 100644 build.sh create mode 100644 resources/test_data.txt create mode 100644 test/Test.java diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..4aabca7 --- /dev/null +++ b/build.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +rm -rf out +mkdir out +javac -encoding utf8 -classpath src/me/theentropyshard/jdarkroom -d out -sourcepath . src/me/theentropyshard/jdarkroom/*.java +cd out +jar cfe0 JDarkroom.jar me.theentropyshard.jdarkroom.Main me/theentropyshard/jdarkroom/*.class -C ../resources . +mv ./JDarkroom.jar ../ +cd ../ \ No newline at end of file diff --git a/resources/readme.txt b/resources/readme.txt index 65a4088..69443ac 100644 --- a/resources/readme.txt +++ b/resources/readme.txt @@ -1,4 +1,4 @@ background.png taken from the Internet, resized and darkened + mdisk.ico taken from https://github.com/9214/daruma, I sent an email asking for -this icon, at the moment of writing this, author still not answered, but the license is -WTFPL, so I think it is OK to take this icon. \ No newline at end of file +this icon. Author permitted me to use it. \ No newline at end of file diff --git a/resources/test_data.txt b/resources/test_data.txt new file mode 100644 index 0000000..ff040d4 --- /dev/null +++ b/resources/test_data.txt @@ -0,0 +1,101 @@ +8a1\wyRVK1L8Z2kZ +o?d\w3R1e1KQVSiP +\tH5Wc8m+Vtk8QWR +8AvLKYqyb5tQJi7h +uCc1FQWyGWdR?tcZ +6!VPg?UQ?RZyhh/a +MquDCP+Tbz+sJHvv +Eg\Fc?AWH4z9\Z77 +\vSJr\hCU7z8R1h! +/1\Hs!UQhcSkx4LN +u6ajbPxQY3SpgW9N +eov8WRNHZ1ckhQWe +uQBGJs4HF4typCNQ +mLT+6ZXy4di?Rkk9 +o\EFd\718zx9tmES +MSG5P&uXAdcsXRnA +uQBGJs4HV4NyDTNQ +E+\qjfLyLb\qxAvB +mRV4UmUWV?PWZaUJ +6d&ZM6b&/3T/rQMA +/S9UcnkyMWs1Hw8i +gbN9E3pEsz/51aEF +uCc1FQWyWW9B8sdZ +mLT+6ZXyYdi?Rsk9 +oKMEd\71MzR9PvES +MquDKP+Tbz+s+HvP +2SBkhhaEs8oZBRHk +8a1\wyRVK1L8Z?kY +c8HYkktToXdusKSL +6d&ZM6b&13T/pcMA +MquDKP+TLzosJGrv +8AvLKYqyb5tQLq7h +EXB\BhaWF6+CAHN/ +Wm\gH3VwXcA4epd8 +mRV4UmUSE6vW5XUJ +kEdUmH/i8QuVx18b +E+\qjfL2Pb\qwKvA +2SJkhhaE84+ZhQnk +Um\gH3VwHcg414dc +WZu&E8HwdWxkawqs +uCc1FQWymWdR?&dZ +?6Stp\&TQfHqStzE +u6ajbPxU+zypAf9N +8a1\wyRFa1r849k5 +/1\Hs!UUhcSkwwLt +mRV4UmUWU?PWYW/J +2S9UUnkyMWs1G/8C +mLT+6ZXy4di?Rs&9 +aQ/Pp3WxEf+Kj9wb +MSG4f&uXAdcsVZmA +MtH5ec8mYVNkWBWR +6d&ZM6bh&zz/KdsA +\vSJr\hWA7T858hf +o?d\w3Rxf1KQXeiP +6!VPo?UQuR5yJ/w6 +\tH5ec8m+VtkXESx +oKMFN\71czxtNuES +8AvLaYqyL5NAJr6h +MquDKP+Tbz+sLDvP +2SBkhhaEs8oZAVHk +/1\Hs!UA1cykRzLM +8ot1?L!V+ZSTkMAy +6dtZM6bh1zT/KYMA +MquDKP+TLzos+Crv +EXBPBhaWV6oSAGN/ +WZu&E8HwtWR/Yxrs +Wm\gH3VwXcA4ftd8 +mRV4UmUSE6vW4TUJ +\vSJr\hGQ7z8Y9h! +E+\qjfL2Lb\qxKvB +2SJkhhaE84+ZgUnk +Um\gH3VwHcg4esZc +uCc/FQWy2W9B8kdZ +uCc/FQWymWdB?&dZ +?6Stp\&TQfHqTpzE +o?d\w3R1PxqQ3fCP +eov8WRNDJx8kAdWe +/1\Hs!UU&cSkxwLt +mRV4UmUWU?PWbS/J +?6Stp\&TAfnq74zk +aQ/\53WxUfoah8wb +aQ/\p3WxEf+aj9wb +MSG5f&uXAdc8XZmA +ibN9M3pE8zU5dLE& +EomojKLQr7vCdbp/ +\vSJr\hSE7T84UhW +o?d\w3Rxf1KQWSiG +eon8WRNDZxckAQ2X +gbN9E3pEsz/5cuQF +qKMEd\71c3x9PmES +?AvKaYqyL9NQJj6h +sQBGJs4HV4NyBzdQ +EgGFc?ASG4z9MZ7y +/1\Hs!UExcykQbLF +8ot1?L!VMZST&kA6 +EouojKLQ77PCdWJ9 +MquDCP+TLzosLm7v +GXB\BhaWV?oCA\N/ +UZukU8HwtSRka5rs +/S9UcnkycWM1&FoC +fCe\w9!iBXJ1ijn& \ No newline at end of file diff --git a/src/me/theentropyshard/jdarkroom/Decoder.java b/src/me/theentropyshard/jdarkroom/Decoder.java index 59c2c81..731cee4 100644 --- a/src/me/theentropyshard/jdarkroom/Decoder.java +++ b/src/me/theentropyshard/jdarkroom/Decoder.java @@ -23,7 +23,7 @@ public enum Decoder { public static String decodeInternetCode(String code) { byte[] bytes = new byte[16]; for(int i = 0; i < 16; i++) { - bytes[i] = DecodingData.CODE_INDEX_TABLE.get(Character.toString(code.charAt(i))); + bytes[i] = DecodingData.FROM_INTERNET_CODE.get(code.charAt(i)); } for(int i = 6; i > 0; i--) { @@ -35,12 +35,10 @@ public enum Decoder { Utils.swapBits(byte1, byte2, bi1, bi2, bytes); } - String bin = Integer.toBinaryString(bytes[bytes.length - 1]); - int index = Integer.parseInt(bin.substring(0, 3), 2); + int index = (bytes[15] >> 3) & 0b111; byte firstRoundKey = DecodingData.KEY[index]; byte secondRoundKey = DecodingData.KEY[DecodingData.KEY.length - 1 - index]; - for(int i = 30; i > 0; i--) { int m = (i * firstRoundKey + 45) % 90; int n = (i * secondRoundKey + 45) % 90; @@ -55,8 +53,7 @@ public enum Decoder { Utils.swapBits(byte1, byte2, bi1, bi2, bytes); } - byte thirdRoundKey = DecodingData.KEY[bytes[bytes.length - 1] & 0b111]; - + byte thirdRoundKey = DecodingData.KEY[bytes[15] & 0b111]; for(int i = 40; i > 0; i--) { int m = i * thirdRoundKey % 90; int n = m % 6; @@ -78,20 +75,23 @@ public enum Decoder { intCode |= (bytes[10] & (0x0000000C >> 2)) << 2; intCode |= (bytes[11] & (0x00000003 << 4)) >> 4; - int l1 = Integer.parseInt(Integer.toHexString((intCode >> 24) & 0xFF), 10); - int d1 = Integer.parseInt(Integer.toHexString((intCode >> 16) & 0xFF), 16); - int l2 = Integer.parseInt(Integer.toHexString((intCode >> 8) & 0xFF), 16); - int d2 = Integer.parseInt(Integer.toHexString((intCode >> 0) & 0xFF), 16); + int l1 = (intCode >> 24) & 0xFF; + int d1 = (intCode >> 16) & 0xFF; + int l2 = (intCode >> 8) & 0xFF; + int d2 = (intCode >> 0) & 0xFF; - String[] letters1 = DecodingData.SAVE_INDEX_TABLE.get(l1 + 1).split("\\s"); - String[] letters2 = DecodingData.SAVE_INDEX_TABLE.get(l2 + 1).split("\\s"); + String[] letters1 = DecodingData.BYTES_TO_CODE.get(Integer.valueOf(l1).byteValue()); + String[] letters2 = DecodingData.BYTES_TO_CODE.get(Integer.valueOf(l2).byteValue()); + // From https://9214.github.io/13 + // "Recall that locker code is stored in letter-digit-letter-digit format – letter + // is a letter index from 0-based A-Z alphabet, and digit is actual digit." String russianCode = letters1[1] + d1 + letters2[1] + d2; String englishCode = letters1[0] + d1 + letters2[0] + d2; + // I could put this in PRSF (private static final), but it might be not initialized yet String russianLabel = I18N.getString("codeLabelRu"); String englishLabel = I18N.getString("codeLabelEn"); - String andText = I18N.getString("andText"); - return String.format("%s: %s %s %s: %s", russianLabel, russianCode, andText, englishLabel, englishCode); + return String.format("%s: %s %s %s: %s", russianLabel, russianCode, I18N.getString("andText"), englishLabel, englishCode); } } diff --git a/src/me/theentropyshard/jdarkroom/DecodingData.java b/src/me/theentropyshard/jdarkroom/DecodingData.java index cbd65e4..58b7656 100644 --- a/src/me/theentropyshard/jdarkroom/DecodingData.java +++ b/src/me/theentropyshard/jdarkroom/DecodingData.java @@ -21,9 +21,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -public final class DecodingData { +public enum DecodingData { + ; + /** - * Offset, where Akuda locker code located + * Offset, where Akuda locker code located in save */ public static final long CODE_OFFSET = 0x00002D58L; @@ -80,76 +82,152 @@ public final class DecodingData { ); /** - * Table for decoding bytes from decoded Internet Code, english and russian letters - * Ok, this is bigger + * Table for decoding Internet Code to bytes, english and russian letters + * Example code: fCe\w9!iBXJ1ijn& */ - public static final Map CODE_INDEX_TABLE = Collections.unmodifiableMap( - new HashMap() {{ + public static final Map FROM_INTERNET_CODE = Collections.unmodifiableMap( + new HashMap() {{ // @formatter:off - this.put("A", (byte) 0); this.put("А", (byte) 0); - this.put("B", (byte) 1); this.put("Б", (byte) 1); - this.put("C", (byte) 2); this.put("Ц", (byte) 2); - this.put("D", (byte) 3); this.put("Д", (byte) 3); - this.put("E", (byte) 4); this.put("Е", (byte) 4); - this.put("F", (byte) 5); this.put("Ф", (byte) 5); - this.put("G", (byte) 6); this.put("Г", (byte) 6); - this.put("H", (byte) 7); this.put("Ю", (byte) 7); - this.put("+", (byte) 8); // this.put("+", (byte) 8); - this.put("J", (byte) 9); this.put("Й", (byte) 9); - this.put("K", (byte) 10); this.put("К", (byte) 10); - this.put("L", (byte) 11); this.put("Л", (byte) 10); - this.put("M", (byte) 12); this.put("М", (byte) 10); - this.put("N", (byte) 13); this.put("Н", (byte) 10); - this.put("\\", (byte) 14); // this.put("\\", (byte) 10); - this.put("P", (byte) 15); this.put("П", (byte) 10); - this.put("Q", (byte) 16); this.put("Я", (byte) 10); - this.put("R", (byte) 17); this.put("Р", (byte) 10); - this.put("S", (byte) 18); this.put("С", (byte) 10); - this.put("T", (byte) 19); this.put("Т", (byte) 10); - this.put("U", (byte) 20); this.put("У", (byte) 10); - this.put("V", (byte) 21); this.put("В", (byte) 10); - this.put("W", (byte) 22); this.put("Ш", (byte) 10); - this.put("X", (byte) 23); this.put("Х", (byte) 10); - this.put("Y", (byte) 24); this.put("Ч", (byte) 10); - this.put("Z", (byte) 25); this.put("Ж", (byte) 10); - this.put("a", (byte) 26); this.put("а", (byte) 10); - this.put("b", (byte) 27); this.put("б", (byte) 10); - this.put("c", (byte) 28); this.put("ц", (byte) 10); - this.put("d", (byte) 29); this.put("д", (byte) 10); - this.put("e", (byte) 30); this.put("е", (byte) 10); - this.put("f", (byte) 31); this.put("ф", (byte) 10); - this.put("g", (byte) 32); this.put("г", (byte) 10); - this.put("h", (byte) 33); this.put("ю", (byte) 10); - this.put("i", (byte) 34); this.put("и", (byte) 10); - this.put("j", (byte) 35); this.put("й", (byte) 10); - this.put("k", (byte) 36); this.put("к", (byte) 10); - this.put("&", (byte) 37); // this.put("&", (byte) 10); - this.put("m", (byte) 38); this.put("м", (byte) 10); - this.put("n", (byte) 39); this.put("н", (byte) 10); - this.put("o", (byte) 40); this.put("о", (byte) 10); - this.put("p", (byte) 41); this.put("п", (byte) 10); - this.put("q", (byte) 42); this.put("я", (byte) 10); - this.put("r", (byte) 43); this.put("р", (byte) 10); - this.put("s", (byte) 44); this.put("с", (byte) 10); - this.put("t", (byte) 45); this.put("т", (byte) 10); - this.put("u", (byte) 46); this.put("у", (byte) 10); - this.put("v", (byte) 47); this.put("в", (byte) 10); - this.put("w", (byte) 48); this.put("ш", (byte) 10); - this.put("x", (byte) 49); this.put("х", (byte) 10); - this.put("y", (byte) 50); this.put("ч", (byte) 10); - this.put("z", (byte) 51); this.put("ж", (byte) 10); - this.put("/", (byte) 52); // this.put("/", (byte) 10); - this.put("1", (byte) 53); // this.put("K", (byte) 10); - this.put("2", (byte) 54); // this.put("K", (byte) 10); - this.put("3", (byte) 55); // this.put("K", (byte) 10); - this.put("4", (byte) 56); // this.put("K", (byte) 10); - this.put("5", (byte) 57); // this.put("K", (byte) 10); - this.put("6", (byte) 58); // this.put("K", (byte) 10); - this.put("7", (byte) 59); // this.put("K", (byte) 10); - this.put("8", (byte) 60); // this.put("K", (byte) 10); - this.put("9", (byte) 61); // this.put("K", (byte) 10); - this.put("?", (byte) 62); // this.put("K", (byte) 10); - this.put("!", (byte) 63); // this.put("K", (byte) 10); + this.put('A', (byte) 0); this.put('А', (byte) 0); + this.put('B', (byte) 1); this.put('Б', (byte) 1); + this.put('C', (byte) 2); this.put('Ц', (byte) 2); + this.put('D', (byte) 3); this.put('Д', (byte) 3); + this.put('E', (byte) 4); this.put('Е', (byte) 4); + this.put('F', (byte) 5); this.put('Ф', (byte) 5); + this.put('G', (byte) 6); this.put('Г', (byte) 6); + this.put('H', (byte) 7); this.put('Ю', (byte) 7); + this.put('+', (byte) 8); + this.put('J', (byte) 9); this.put('Й', (byte) 9); + this.put('K', (byte) 10); this.put('К', (byte) 10); + this.put('L', (byte) 11); this.put('Л', (byte) 11); + this.put('M', (byte) 12); this.put('М', (byte) 12); + this.put('N', (byte) 13); this.put('Н', (byte) 13); + this.put('\\', (byte) 14); + this.put('P', (byte) 15); this.put('П', (byte) 15); + this.put('Q', (byte) 16); this.put('Я', (byte) 16); + this.put('R', (byte) 17); this.put('Р', (byte) 17); + this.put('S', (byte) 18); this.put('С', (byte) 18); + this.put('T', (byte) 19); this.put('Т', (byte) 19); + this.put('U', (byte) 20); this.put('У', (byte) 20); + this.put('V', (byte) 21); this.put('В', (byte) 21); + this.put('W', (byte) 22); this.put('Ш', (byte) 22); + this.put('X', (byte) 23); this.put('Х', (byte) 23); + this.put('Y', (byte) 24); this.put('Ч', (byte) 24); + this.put('Z', (byte) 25); this.put('Ж', (byte) 25); + this.put('a', (byte) 26); this.put('а', (byte) 26); + this.put('b', (byte) 27); this.put('б', (byte) 27); + this.put('c', (byte) 28); this.put('ц', (byte) 28); + this.put('d', (byte) 29); this.put('д', (byte) 29); + this.put('e', (byte) 30); this.put('е', (byte) 30); + this.put('f', (byte) 31); this.put('ф', (byte) 31); + this.put('g', (byte) 32); this.put('г', (byte) 32); + this.put('h', (byte) 33); this.put('ю', (byte) 33); + this.put('i', (byte) 34); this.put('и', (byte) 34); + this.put('j', (byte) 35); this.put('й', (byte) 35); + this.put('k', (byte) 36); this.put('к', (byte) 36); + this.put('&', (byte) 37); + this.put('m', (byte) 38); this.put('м', (byte) 38); + this.put('n', (byte) 39); this.put('н', (byte) 39); + this.put('o', (byte) 40); this.put('о', (byte) 40); + this.put('p', (byte) 41); this.put('п', (byte) 41); + this.put('q', (byte) 42); this.put('я', (byte) 42); + this.put('r', (byte) 43); this.put('р', (byte) 43); + this.put('s', (byte) 44); this.put('с', (byte) 44); + this.put('t', (byte) 45); this.put('т', (byte) 45); + this.put('u', (byte) 46); this.put('у', (byte) 46); + this.put('v', (byte) 47); this.put('в', (byte) 47); + this.put('w', (byte) 48); this.put('ш', (byte) 48); + this.put('x', (byte) 49); this.put('х', (byte) 49); + this.put('y', (byte) 50); this.put('ч', (byte) 50); + this.put('z', (byte) 51); this.put('ж', (byte) 51); + this.put('/', (byte) 52); + this.put('1', (byte) 53); + this.put('2', (byte) 54); + this.put('3', (byte) 55); + this.put('4', (byte) 56); + this.put('5', (byte) 57); + this.put('6', (byte) 58); + this.put('7', (byte) 59); + this.put('8', (byte) 60); + this.put('9', (byte) 61); + this.put('?', (byte) 62); + this.put('!', (byte) 63); + // @formatter:on + }} + ); + + /** + * Table for transforming bytes into game code + * Format of code: letter-digit-letter-digit
+ * Example: N5K9 + */ + public static final Map BYTES_TO_CODE = Collections.unmodifiableMap( + new HashMap() {{ + // @formatter:off + this.put((byte) 0, new String[]{"A", "А"}); + this.put((byte) 1, new String[]{"B", "Б"}); + this.put((byte) 2, new String[]{"C", "Ц"}); + this.put((byte) 3, new String[]{"D", "Д"}); + this.put((byte) 4, new String[]{"E", "Е"}); + this.put((byte) 5, new String[]{"F", "Ф"}); + this.put((byte) 6, new String[]{"G", "Г"}); + this.put((byte) 7, new String[]{"H", "Ю"}); + this.put((byte) 8, new String[]{"+", "+"}); + this.put((byte) 9, new String[]{"J", "Й"}); + this.put((byte) 10, new String[]{"K", "К"}); + this.put((byte) 11, new String[]{"L", "Л"}); + this.put((byte) 12, new String[]{"M", "М"}); + this.put((byte) 13, new String[]{"N", "Н"}); + this.put((byte) 14, new String[]{"\\", "\\"}); + this.put((byte) 15, new String[]{"P", "П"}); + this.put((byte) 16, new String[]{"Q", "Я"}); + this.put((byte) 17, new String[]{"R", "Р"}); + this.put((byte) 18, new String[]{"S", "С"}); + this.put((byte) 19, new String[]{"T", "Т"}); + this.put((byte) 20, new String[]{"U", "У"}); + this.put((byte) 21, new String[]{"V", "В"}); + this.put((byte) 22, new String[]{"W", "Ш"}); + this.put((byte) 23, new String[]{"X", "Х"}); + this.put((byte) 24, new String[]{"Y", "Ч"}); + this.put((byte) 25, new String[]{"Z", "Ж"}); + this.put((byte) 26, new String[]{"a", "а"}); + this.put((byte) 27, new String[]{"b", "б"}); + this.put((byte) 28, new String[]{"c", "ц"}); + this.put((byte) 29, new String[]{"d", "д"}); + this.put((byte) 30, new String[]{"e", "е"}); + this.put((byte) 31, new String[]{"f", "ф"}); + this.put((byte) 32, new String[]{"g", "г"}); + this.put((byte) 33, new String[]{"h", "ю"}); + this.put((byte) 34, new String[]{"i", "и"}); + this.put((byte) 35, new String[]{"j", "й"}); + this.put((byte) 36, new String[]{"k", "к"}); + this.put((byte) 37, new String[]{"&", "&"}); + this.put((byte) 38, new String[]{"m", "м"}); + this.put((byte) 39, new String[]{"n", "н"}); + this.put((byte) 40, new String[]{"o", "о"}); + this.put((byte) 41, new String[]{"p", "п"}); + this.put((byte) 42, new String[]{"q", "я"}); + this.put((byte) 43, new String[]{"r", "р"}); + this.put((byte) 44, new String[]{"s", "с"}); + this.put((byte) 45, new String[]{"t", "т"}); + this.put((byte) 46, new String[]{"u", "у"}); + this.put((byte) 47, new String[]{"v", "в"}); + this.put((byte) 48, new String[]{"w", "ш"}); + this.put((byte) 49, new String[]{"x", "х"}); + this.put((byte) 50, new String[]{"y", "ч"}); + this.put((byte) 51, new String[]{"z", "ж"}); + this.put((byte) 52, new String[]{"/", "/"}); + this.put((byte) 53, new String[]{"1", "1"}); + this.put((byte) 54, new String[]{"2", "2"}); + this.put((byte) 55, new String[]{"3", "3"}); + this.put((byte) 56, new String[]{"4", "4"}); + this.put((byte) 57, new String[]{"5", "5"}); + this.put((byte) 58, new String[]{"6", "6"}); + this.put((byte) 59, new String[]{"7", "7"}); + this.put((byte) 60, new String[]{"8", "8"}); + this.put((byte) 61, new String[]{"9", "9"}); + this.put((byte) 62, new String[]{"?", "?"}); + this.put((byte) 63, new String[]{"!", "!"}); // @formatter:on }} ); diff --git a/src/me/theentropyshard/jdarkroom/I18N.java b/src/me/theentropyshard/jdarkroom/I18N.java index 1ac25a0..d05951f 100644 --- a/src/me/theentropyshard/jdarkroom/I18N.java +++ b/src/me/theentropyshard/jdarkroom/I18N.java @@ -56,9 +56,9 @@ public enum I18N { } public static String getString(String key) { - if(key.indexOf(".") == 2) { + /*if(key.indexOf(".") == 2) { return I18N.TRANSLATION.get(key); - } + }*/ return I18N.TRANSLATION.get(I18N.LANGUAGE + "." + key); } } diff --git a/src/me/theentropyshard/jdarkroom/Utils.java b/src/me/theentropyshard/jdarkroom/Utils.java index 36071eb..e4892d8 100644 --- a/src/me/theentropyshard/jdarkroom/Utils.java +++ b/src/me/theentropyshard/jdarkroom/Utils.java @@ -70,4 +70,10 @@ public enum Utils { bytes[byteInd1] |= 1 << bi1; } } + + /*public static final class StrIntBiMap extends HashMap { + public Integer getValueByKey(String key) { + + } + }*/ } diff --git a/test/Test.java b/test/Test.java new file mode 100644 index 0000000..88f8a59 --- /dev/null +++ b/test/Test.java @@ -0,0 +1,23 @@ +import me.theentropyshard.jdarkroom.Decoder; + +import java.util.Objects; +import java.util.Scanner; + +public class Test { + public static void main(String[] args) { + try { + Scanner scanner = new Scanner(Objects.requireNonNull(Test.class.getResourceAsStream("/test_data.txt"))); + for(int i = 1; scanner.hasNextLine(); i++) { + String code = scanner.nextLine(); + if(code.length() != 16) { + System.err.println("Found illegal test code in test_data.txt: " + code + ", line=" + i + ", length=" + code.length()); + continue; + } + String decoded = Decoder.decodeInternetCode(code); + System.out.println("Successfully decoded: " + code + " into " + decoded); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +}