From 34160dbf0d5c3d4fdc088d35ddb53f8fef0455b6 Mon Sep 17 00:00:00 2001 From: PiggyMoe Date: Sat, 23 May 2020 01:00:25 +0800 Subject: [PATCH 1/2] Add Baudot operations --- src/core/config/Categories.json | 4 +- src/core/operations/FromBaudotCode.mjs | 91 ++++++++++++++++++++ src/core/operations/ToBaudotCode.mjs | 110 +++++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/BaudotCode.mjs | 56 +++++++++++++ 5 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/FromBaudotCode.mjs create mode 100644 src/core/operations/ToBaudotCode.mjs create mode 100644 tests/operations/tests/BaudotCode.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 77e3d319..e6457687 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -116,7 +116,9 @@ "Multiple Bombe", "Typex", "Lorenz", - "Colossus" + "Colossus", + "To Baudot Code", + "From Baudot Code" ] }, { diff --git a/src/core/operations/FromBaudotCode.mjs b/src/core/operations/FromBaudotCode.mjs new file mode 100644 index 00000000..cd1d4a7e --- /dev/null +++ b/src/core/operations/FromBaudotCode.mjs @@ -0,0 +1,91 @@ +/** + * @author piggymoe [me@piggy.moe] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * From Baudot Code operation + */ +class FromBaudotCode extends Operation { + + /** + * FromBaudotCode constructor + */ + constructor() { + super(); + + this.name = "From Baudot Code"; + this.module = "Default"; + this.description = "Translates Baudot code to (upper case) characters using International Telegraph Alphabet No. 2 (ITA2)."; + this.infoURL = "https://wikipedia.org/wiki/Baudot_code"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Endianness", + "type": "option", + "value": ["Big-endian", "Little-endian"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const isLittleEndian = args[0] === "Little-endian"; + + let output = ""; + + let currentTable = LETTER_TABLE; + let bits = 0; + let value = 0; + + for (let i = 0; i < input.length; i++) { + const char = input[i]; + if (char !== "0" && char !== "1") { + continue; + } + if (!isLittleEndian) { + value = value * 2 + parseInt(char, 2); + } else { + value = (parseInt(char, 2) << bits) + value; + } + bits++; + if (bits === 5) { + switch (value) { + case LETTER_TABLE.marker: + currentTable = LETTER_TABLE; + break; + case FIGURE_TABLE.marker: + currentTable = FIGURE_TABLE; + break; + default: + output += currentTable.data[value]; + } + bits = 0; + value = 0; + } + } + + return output; + } + +} + +const LETTER_TABLE = { + marker: 0x1f, + data: "\x00\x45\x0a\x41\x20\x53\x49\x55\x0d\x44\x52\x4a\x4e\x46\x43\x4b\x54\x5a\x4c\x57\x48\x59\x50\x51\x4f\x42\x47\x0e\x4d\x58\x56\x0f" +}; + +const FIGURE_TABLE = { + marker: 0x1b, + data: "\x00\x33\x0a\x2d\x20\x27\x38\x37\x0d\x05\x34\x07\x2c\x21\x3a\x28\x35\x2b\x29\x32\xa3\x36\x30\x31\x39\x3f\x26\x0e\x2e\x2f\x3d\x0f" +}; + +export default FromBaudotCode; diff --git a/src/core/operations/ToBaudotCode.mjs b/src/core/operations/ToBaudotCode.mjs new file mode 100644 index 00000000..84aeb633 --- /dev/null +++ b/src/core/operations/ToBaudotCode.mjs @@ -0,0 +1,110 @@ +/** + * @author piggymoe [me@piggy.moe] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * To Baudot Code operation + */ +class ToBaudotCode extends Operation { + + /** + * ToBaudotCode constructor + */ + constructor() { + super(); + + this.name = "To Baudot Code"; + this.module = "Default"; + this.description = "Translates characters into Baudot code using International Telegraph Alphabet No. 2 (ITA2).

Ignores non-Baudot characters.

e.g. BAUDOT becomes 11001 00011 00111 01001 11000 10000"; + this.infoURL = "https://wikipedia.org/wiki/Baudot_code"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Endianness", + "type": "option", + "value": ["Big-endian", "Little-endian"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + if (!this.initialized) { + this.initialize(); + } + + let output = []; + let currentTable = LETTER_TABLE; + let anotherTable = FIGURE_TABLE; + + for (let i = 0; i < input.length; i++) { + const char = input[i].toUpperCase(); + let signal = currentTable.reverse[char]; + if (signal !== undefined) { + output.push(signal); + continue; + } + signal = anotherTable.reverse[char]; + if (signal === undefined) { + continue; + } + [currentTable, anotherTable] = [anotherTable, currentTable]; + output.push(currentTable.marker); + output.push(signal); + } + + if (args[0] === "Little-endian") { + output = output.map((x) => (((x & 1) << 4) ^ ((x & 2) << 2) ^ (x & 4) ^ ((x & 8) >> 2) ^ ((x & 16) >> 4))); + } + + return output + .map((x) => x.toString(2).padStart(5, "0")) + .join(" "); + } + + /** + * Initialize all Baudot Code lookup table + */ + initialize() { + this.initialized = true; + this.initializeTable(LETTER_TABLE); + this.initializeTable(FIGURE_TABLE); + } + + /** + * Initialize one Baudot Code lookup table + * @param table the table to initialize + */ + initializeTable(table) { + for (let i = 0; i < table.data.length; i++) { + const signal = table.data[i]; + table.reverse[signal] = i; + } + } + +} + +const LETTER_TABLE = { + marker: 0x1f, + data: "\x00\x45\x0a\x41\x20\x53\x49\x55\x0d\x44\x52\x4a\x4e\x46\x43\x4b" + + "\x54\x5a\x4c\x57\x48\x59\x50\x51\x4f\x42\x47\x0e\x4d\x58\x56\x0f", + reverse: {} +}; + +const FIGURE_TABLE = { + marker: 0x1b, + data: "\x00\x33\x0a\x2d\x20\x27\x38\x37\x0d\x05\x34\x07\x2c\x21\x3a\x28" + + "\x35\x2b\x29\x32\xa3\x36\x30\x31\x39\x3f\x26\x0e\x2e\x2f\x3d\x0f", + reverse: {} +}; + +export default ToBaudotCode; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 8d3cd623..e563bb63 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -23,6 +23,7 @@ import "./tests/BaconCipher.mjs"; import "./tests/Base58.mjs"; import "./tests/Base64.mjs"; import "./tests/Base62.mjs"; +import "./tests/BaudotCode.mjs"; import "./tests/BitwiseOp.mjs"; import "./tests/ByteRepr.mjs"; import "./tests/CartesianProduct.mjs"; diff --git a/tests/operations/tests/BaudotCode.mjs b/tests/operations/tests/BaudotCode.mjs new file mode 100644 index 00000000..76d7d2b1 --- /dev/null +++ b/tests/operations/tests/BaudotCode.mjs @@ -0,0 +1,56 @@ +/** + * Baudot code tests. + * + * @author piggymoe [me@piggy.moe] + * + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "To Baudot Code (BE)", + input: "1+1 EQUALS 2", + expectedOutput: "11011 10111 10001 10111 00100 11111 00001 10111 00111 00011 10010 00101 00100 11011 10011", + recipeConfig: [ + { + op: "To Baudot Code", + args: ["Big-endian"], + }, + ], + }, + { + name: "To Baudot Code (LE)", + input: "1+1 EQUALS 2", + expectedOutput: "11011 11101 10001 11101 00100 11111 10000 11101 11100 11000 01001 10100 00100 11011 11001", + recipeConfig: [ + { + op: "To Baudot Code", + args: ["Little-endian"], + }, + ], + }, + { + name: "From Baudot Code (BE)", + input: "11011 10111 10001 10111 00100 11111 00001 10111 00111 00011 10010 00101 00100 11011 10011", + expectedOutput: "1+1 EQUALS 2", + recipeConfig: [ + { + op: "From Baudot Code", + args: ["Big-endian"], + }, + ], + }, + { + name: "From Baudot Code (LE)", + input: "11011 11101 10001 11101 00100 11111 10000 11101 11100 11000 01001 10100 00100 11011 11001", + expectedOutput: "1+1 EQUALS 2", + recipeConfig: [ + { + op: "From Baudot Code", + args: ["Little-endian"], + }, + ], + }, +]); From 4f26b3008dd14228745c715de06e113237a4f4a2 Mon Sep 17 00:00:00 2001 From: PiggyMoe Date: Fri, 12 Jun 2020 23:24:24 +0800 Subject: [PATCH 2/2] Empty commit intended to re-run CI test