diff --git a/package-lock.json b/package-lock.json
index caaa90b2..02ed1af7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6709,9 +6709,9 @@
}
},
"mkdirp": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz",
- "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true
},
"resolve": {
diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 77e3d319..bc109430 100755
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -341,7 +341,8 @@
"CRC-8 Checksum",
"CRC-16 Checksum",
"CRC-32 Checksum",
- "TCP/IP Checksum"
+ "TCP/IP Checksum",
+ "Parity Bit"
]
},
{
diff --git a/src/core/lib/ParityBit.mjs b/src/core/lib/ParityBit.mjs
new file mode 100644
index 00000000..342631a1
--- /dev/null
+++ b/src/core/lib/ParityBit.mjs
@@ -0,0 +1,41 @@
+/**
+ * Parity Bit functions.
+ *
+ * @author j83305 [awz22@protonmail.com]
+ * @copyright Crown Copyright 2020
+ * @license Apache-2.0
+ *
+ */
+
+import OperationError from "../errors/OperationError.mjs";
+
+export function calculateParityBit(input, args) {
+ let count1s = 0;
+ for (let i = 0; i < input.length; i++){
+ const character = input.charAt(i);
+ if (character === "1"){
+ count1s++;
+ } else if (character !== args[3] && character !== "0" && character !== " "){
+ throw new OperationError("unexpected character encountered: \"" + character + "\"");
+ }
+ }
+ let parityBit = "1";
+ const flipflop = args[0] === "Even Parity" ? 0 : 1;
+ if (count1s % 2 === flipflop){
+ parityBit = "0";
+ }
+ if (args[1] === "End"){
+ return input + parityBit;
+ }else{
+ return parityBit + input;
+ }
+}
+
+// just removes the parity bit to return the original data
+export function decodeParityBit(input, args) {
+ if (args[1] === "End"){
+ return input.slice(0, -1);
+ }else{
+ return input.slice(1);
+ }
+}
\ No newline at end of file
diff --git a/src/core/operations/ParityBit.mjs b/src/core/operations/ParityBit.mjs
new file mode 100644
index 00000000..a27574f2
--- /dev/null
+++ b/src/core/operations/ParityBit.mjs
@@ -0,0 +1,123 @@
+/**
+ * @author j83305 [awz22@protonmail.com]
+ * @copyright Crown Copyright 2020
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import { calculateParityBit, decodeParityBit } from "../lib/ParityBit.mjs";
+
+/**
+ * Parity Bit operation
+ */
+class ParityBit extends Operation {
+
+ /**
+ * ParityBit constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Parity Bit";
+ this.module = "Default";
+ this.description = "A parity bit, or check bit, is the simplest form of error detection. It is a bit which is added to a string of bits and represents if the number of 1's in the binary string is an even number or odd number.
If a delimiter is specified, the parity bit calculation will be performed on each 'block' of the input data, where the blocks are created by slicing the input at each occurence of the delimiter character";
+ this.infoURL = "https://wikipedia.org/wiki/Parity_bit";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ name: "Mode",
+ type: "option",
+ value: [
+ "Even Parity",
+ "Odd Parity"
+ ]
+ },
+ {
+ name: "Postion",
+ type: "option",
+ value: [
+ "Start",
+ "End"
+ ]
+ },
+ {
+ name: "Encode or Decode",
+ type: "option",
+ value: [
+ "Encode",
+ "Decode"
+ ]
+ },
+ {
+ name: "Delimiter",
+ type: "shortString",
+ value: ""
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ if (input.length === 0){
+ return input;
+ }
+ const method = (input, args) => args[2] === "Encode" ? calculateParityBit(input, args) : decodeParityBit(input, args);
+ if (args[3].length > 0){
+ let byteStrings = input.split(args[3]);
+ for (let byteStringsArrayIndex = 0; byteStringsArrayIndex < byteStrings.length; byteStringsArrayIndex++){
+ byteStrings[byteStringsArrayIndex] = method(byteStrings[byteStringsArrayIndex], args);
+ }
+ return byteStrings.join(args[3])
+ }
+ return method(input, args);
+ }
+
+ /**
+ * Highlight Parity Bit
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlight(pos, args) {
+ if (args[3].length === 0){
+ if (args[1] === "Prepend"){
+ pos[0].start += 1;
+ pos[0].end += 1;
+ }
+ return pos;
+ }
+ // need to be able to read input to do the highlighting when there is a delimiter
+ }
+
+ /**
+ * Highlight Parity Bit in reverse
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlightReverse(pos, args) {
+ if (args[3].length === 0){
+ if (args[1] === "Prepend"){
+ if (pos[0].start > 0){
+ pos[0].start -= 1;
+ }
+ pos[0].end -= 1;
+ }
+ return pos;
+ }
+ }
+
+}
+
+export default ParityBit;
diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs
index 8d3cd623..c9fb2f88 100644
--- a/tests/operations/index.mjs
+++ b/tests/operations/index.mjs
@@ -64,6 +64,7 @@ import "./tests/NormaliseUnicode.mjs";
import "./tests/OTP.mjs";
import "./tests/PGP.mjs";
import "./tests/PHP.mjs";
+import "./tests/ParityBit.mjs";
import "./tests/ParseIPRange.mjs";
import "./tests/ParseQRCode.mjs";
import "./tests/PowerSet.mjs";
diff --git a/tests/operations/tests/ParityBit.mjs b/tests/operations/tests/ParityBit.mjs
new file mode 100644
index 00000000..bc42b9f8
--- /dev/null
+++ b/tests/operations/tests/ParityBit.mjs
@@ -0,0 +1,147 @@
+/**
+ * Parity Bit tests
+ *
+ * @author j83305 [awz22@protonmail.com]
+ * @copyright Crown Copyright 2020
+ * @license Apache-2.0
+ */
+import TestRegister from "../../lib/TestRegister.mjs";
+
+TestRegister.addTests([
+ {
+ name: "Parity bit encode in even parity, 1 block of binary of arbitrary length, prepend, even number of 1s",
+ input: "01010101 10101010",
+ expectedOutput: "001010101 10101010",
+ recipeConfig: [
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Even Parity",
+ "Start",
+ "Encode",
+ ""
+ ]
+ }
+ ]
+ },
+ {
+ name: "Parity bit encode in even parity, 1 block of binary of arbitrary length, prepend, odd number of 1s",
+ input: "01010101 10101011",
+ expectedOutput: "101010101 10101011",
+ recipeConfig: [
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Even Parity",
+ "Start",
+ "Encode",
+ ""
+ ]
+ }
+ ]
+ },
+ {
+ name: "Parity bit encode in even parity, 1 block of binary of arbitrary length, append, odd number of 1s",
+ input: "01010101 10101011",
+ expectedOutput: "01010101 101010111",
+ recipeConfig: [
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Even Parity",
+ "End",
+ "Encode",
+ ""
+ ]
+ }
+ ]
+ },
+ {
+ name: "Parity bit encode in odd parity, 1 block of binary of arbitrary length, prepend, even number of 1s",
+ input: "01010101 10101010",
+ expectedOutput: "101010101 10101010",
+ recipeConfig: [
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Odd Parity",
+ "Start",
+ "Encode",
+ ""
+ ]
+ }
+ ]
+ },
+ {
+ name: "Parity bit encode in odd parity, 1 block of binary of arbitrary length, prepend, odd number of 1s",
+ input: "01010101 10101011",
+ expectedOutput: "001010101 10101011",
+ recipeConfig: [
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Odd Parity",
+ "Start",
+ "Encode",
+ ""
+ ]
+ }
+ ]
+ },
+ {
+ name: "Parity bit encode in odd parity, 1 block of binary of arbitrary length, append, odd number of 1s",
+ input: "01010101 10101011",
+ expectedOutput: "01010101 101010110",
+ recipeConfig: [
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Odd Parity",
+ "End",
+ "Encode",
+ ""
+ ]
+ }
+ ]
+ },
+ {
+ name: "Parity bit encode in even parity, binary for 'hello world!', prepend to each byte",
+ input: "hello world!",
+ expectedOutput: "101101000 001100101 001101100 001101100 001101111 100100000 001110111 001101111 001110010 001101100 101100100 000100001",
+ recipeConfig: [
+ {
+ "op": "To Binary",
+ "args": ["Space"]
+ },
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Even Parity",
+ "Start",
+ "Encode",
+ " "
+ ]
+ }
+ ]
+ },
+ {
+ name: "Parity bit encode in odd parity, binary for 'hello world!', append to each byte",
+ input: "hello world!",
+ expectedOutput: "011010000 011001011 011011001 011011001 011011111 001000000 011101111 011011111 011100101 011011001 011001000 001000011",
+ recipeConfig: [
+ {
+ "op": "To Binary",
+ "args": ["Space"]
+ },
+ {
+ "op": "Parity Bit",
+ "args": [
+ "Odd Parity",
+ "End",
+ "Encode",
+ " "
+ ]
+ }
+ ]
+ },
+]);