diff --git a/src/core/lib/Delim.mjs b/src/core/lib/Delim.mjs
new file mode 100644
index 00000000..ab84f276
--- /dev/null
+++ b/src/core/lib/Delim.mjs
@@ -0,0 +1,17 @@
+/**
+ * Various delimiters
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+/**
+ * Generic sequence delimiters.
+ */
+export const DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF"];
+
+/**
+ * Binary sequence delimiters.
+ */
+export const BIN_DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "None"];
diff --git a/src/core/operations/FromBinary.mjs b/src/core/operations/FromBinary.mjs
new file mode 100644
index 00000000..ee585bc1
--- /dev/null
+++ b/src/core/operations/FromBinary.mjs
@@ -0,0 +1,87 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {BIN_DELIM_OPTIONS} from "../lib/Delim";
+
+/**
+ * From Binary operation
+ */
+class FromBinary extends Operation {
+
+ /**
+ * FromBinary constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "From Binary";
+ this.module = "Default";
+ this.description = "Converts a binary string back into its raw form.
e.g. 01001000 01101001
becomes Hi
";
+ this.inputType = "string";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": BIN_DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ const delimRegex = Utils.regexRep(args[0] || "Space");
+ input = input.replace(delimRegex, "");
+
+ const output = [];
+ const byteLen = 8;
+ for (let i = 0; i < input.length; i += byteLen) {
+ output.push(parseInt(input.substr(i, byteLen), 2));
+ }
+ return output;
+ }
+
+ /**
+ * Highlight From Binary
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlight(pos, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+ pos[0].start = pos[0].start === 0 ? 0 : Math.floor(pos[0].start / (8 + delim.length));
+ pos[0].end = pos[0].end === 0 ? 0 : Math.ceil(pos[0].end / (8 + delim.length));
+ return pos;
+ }
+
+ /**
+ * Highlight From Binary in reverse
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlightReverse(pos, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+ pos[0].start = pos[0].start * (8 + delim.length);
+ pos[0].end = pos[0].end * (8 + delim.length) - delim.length;
+ return pos;
+ }
+
+}
+
+export default FromBinary;
diff --git a/src/core/operations/FromCharcode.mjs b/src/core/operations/FromCharcode.mjs
new file mode 100644
index 00000000..ed2197bc
--- /dev/null
+++ b/src/core/operations/FromCharcode.mjs
@@ -0,0 +1,80 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+
+/**
+ * From Charcode operation
+ */
+class FromCharcode extends Operation {
+
+ /**
+ * FromCharcode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "From Charcode";
+ this.module = "Default";
+ this.description = "Converts unicode character codes back into text.
e.g. 0393 03b5 03b9 03ac 20 03c3 03bf 03c5
becomes Γειά σου
";
+ this.inputType = "string";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": DELIM_OPTIONS
+ },
+ {
+ "name": "Base",
+ "type": "number",
+ "value": 16
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0] || "Space"),
+ base = args[1];
+ let bites = input.split(delim),
+ i = 0;
+
+ if (base < 2 || base > 36) {
+ throw "Error: Base argument must be between 2 and 36";
+ }
+
+ if (input.length === 0) {
+ return [];
+ }
+
+ if (base !== 16 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
+
+ // Split into groups of 2 if the whole string is concatenated and
+ // too long to be a single character
+ if (bites.length === 1 && input.length > 17) {
+ bites = [];
+ for (i = 0; i < input.length; i += 2) {
+ bites.push(input.slice(i, i+2));
+ }
+ }
+
+ let latin1 = "";
+ for (i = 0; i < bites.length; i++) {
+ latin1 += Utils.chr(parseInt(bites[i], base));
+ }
+ return Utils.strToByteArray(latin1);
+ }
+
+}
+
+export default FromCharcode;
diff --git a/src/core/operations/FromDecimal.mjs b/src/core/operations/FromDecimal.mjs
new file mode 100644
index 00000000..4577a65d
--- /dev/null
+++ b/src/core/operations/FromDecimal.mjs
@@ -0,0 +1,56 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+
+/**
+ * From Decimal operation
+ */
+class FromDecimal extends Operation {
+
+ /**
+ * FromDecimal constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "From Decimal";
+ this.module = "Default";
+ this.description = "Converts the data from an ordinal integer array back into its raw form.
e.g. 72 101 108 108 111
becomes Hello
";
+ this.inputType = "string";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0]),
+ output = [];
+ let byteStr = input.split(delim);
+ if (byteStr[byteStr.length-1] === "")
+ byteStr = byteStr.slice(0, byteStr.length-1);
+
+ for (let i = 0; i < byteStr.length; i++) {
+ output[i] = parseInt(byteStr[i], 10);
+ }
+ return output;
+ }
+
+}
+
+export default FromDecimal;
diff --git a/src/core/operations/FromHexContent.mjs b/src/core/operations/FromHexContent.mjs
new file mode 100644
index 00000000..9de085db
--- /dev/null
+++ b/src/core/operations/FromHexContent.mjs
@@ -0,0 +1,66 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {fromHex} from "../lib/Hex";
+
+/**
+ * From Hex Content operation
+ */
+class FromHexContent extends Operation {
+
+ /**
+ * FromHexContent constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "From Hex Content";
+ this.module = "Default";
+ this.description = "Translates hexadecimal bytes in text back to raw bytes.
e.g. foo|3d|bar
becomes foo=bar
.";
+ this.inputType = "string";
+ this.outputType = "byteArray";
+ this.args = [];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ const regex = /\|([a-f\d ]{2,})\|/gi,
+ output = [];
+ let m, i = 0;
+ while ((m = regex.exec(input))) {
+ // Add up to match
+ for (; i < m.index;)
+ output.push(Utils.ord(input[i++]));
+
+ // Add match
+ const bytes = fromHex(m[1]);
+ if (bytes) {
+ for (let a = 0; a < bytes.length;)
+ output.push(bytes[a++]);
+ } else {
+ // Not valid hex, print as normal
+ for (; i < regex.lastIndex;)
+ output.push(Utils.ord(input[i++]));
+ }
+
+ i = regex.lastIndex;
+ }
+ // Add all after final match
+ for (; i < input.length;)
+ output.push(Utils.ord(input[i++]));
+
+ return output;
+ }
+
+}
+
+export default FromHexContent;
diff --git a/src/core/operations/FromOctal.mjs b/src/core/operations/FromOctal.mjs
new file mode 100644
index 00000000..131e97c5
--- /dev/null
+++ b/src/core/operations/FromOctal.mjs
@@ -0,0 +1,49 @@
+/**
+ * @author Matt C [matt@artemisbot.uk]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+
+/**
+ * From Octal operation
+ */
+class FromOctal extends Operation {
+
+ /**
+ * FromOctal constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "From Octal";
+ this.module = "Default";
+ this.description = "Converts an octal byte string back into its raw value.
e.g. 316 223 316 265 316 271 316 254 40 317 203 316 277 317 205
becomes the UTF-8 encoded string Γειά σου
";
+ this.inputType = "string";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+ if (input.length === 0) return [];
+ return input.split(delim).map(val => parseInt(val, 8));
+ }
+
+}
+
+export default FromOctal;
diff --git a/src/core/operations/ToBinary.mjs b/src/core/operations/ToBinary.mjs
new file mode 100644
index 00000000..f10f66a7
--- /dev/null
+++ b/src/core/operations/ToBinary.mjs
@@ -0,0 +1,91 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {BIN_DELIM_OPTIONS} from "../lib/Delim";
+
+/**
+ * To Binary operation
+ */
+class ToBinary extends Operation {
+
+ /**
+ * ToBinary constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "To Binary";
+ this.module = "Default";
+ this.description = "Displays the input data as a binary string.
e.g. Hi
becomes 01001000 01101001
";
+ this.inputType = "byteArray";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": BIN_DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {byteArray} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0] || "Space"),
+ padding = 8;
+ let output = "";
+
+ for (let i = 0; i < input.length; i++) {
+ output += input[i].toString(2).padStart(padding, "0") + delim;
+ }
+
+ if (delim.length) {
+ return output.slice(0, -delim.length);
+ } else {
+ return output;
+ }
+ }
+
+ /**
+ * Highlight To Binary
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlight(pos, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+ pos[0].start = pos[0].start * (8 + delim.length);
+ pos[0].end = pos[0].end * (8 + delim.length) - delim.length;
+ return pos;
+ }
+
+ /**
+ * Highlight To Binary in reverse
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlightReverse(pos, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+ pos[0].start = pos[0].start === 0 ? 0 : Math.floor(pos[0].start / (8 + delim.length));
+ pos[0].end = pos[0].end === 0 ? 0 : Math.ceil(pos[0].end / (8 + delim.length));
+ return pos;
+ }
+
+}
+
+export default ToBinary;
diff --git a/src/core/operations/ToCharcode.mjs b/src/core/operations/ToCharcode.mjs
new file mode 100644
index 00000000..c6943e90
--- /dev/null
+++ b/src/core/operations/ToCharcode.mjs
@@ -0,0 +1,82 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+
+/**
+ * To Charcode operation
+ */
+class ToCharcode extends Operation {
+
+ /**
+ * ToCharcode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "To Charcode";
+ this.module = "Default";
+ this.description = "Converts text to its unicode character code equivalent.
e.g. Γειά σου
becomes 0393 03b5 03b9 03ac 20 03c3 03bf 03c5
";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": DELIM_OPTIONS
+ },
+ {
+ "name": "Base",
+ "type": "number",
+ "value": 16
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0] || "Space"),
+ base = args[1];
+ let output = "",
+ padding = 2,
+ ordinal;
+
+ if (base < 2 || base > 36) {
+ throw "Error: Base argument must be between 2 and 36";
+ }
+
+ const charcode = Utils.strToCharcode(input);
+ for (let i = 0; i < charcode.length; i++) {
+ ordinal = charcode[i];
+
+ if (base === 16) {
+ if (ordinal < 256) padding = 2;
+ else if (ordinal < 65536) padding = 4;
+ else if (ordinal < 16777216) padding = 6;
+ else if (ordinal < 4294967296) padding = 8;
+ else padding = 2;
+
+ if (padding > 2 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
+
+ output += Utils.hex(ordinal, padding) + delim;
+ } else {
+ if (ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
+ output += ordinal.toString(base) + delim;
+ }
+ }
+
+ return output.slice(0, -delim.length);
+ }
+
+}
+
+export default ToCharcode;
diff --git a/src/core/operations/ToDecimal.mjs b/src/core/operations/ToDecimal.mjs
new file mode 100644
index 00000000..cad8dc18
--- /dev/null
+++ b/src/core/operations/ToDecimal.mjs
@@ -0,0 +1,49 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+
+
+/**
+ * To Decimal operation
+ */
+class ToDecimal extends Operation {
+
+ /**
+ * ToDecimal constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "To Decimal";
+ this.module = "Default";
+ this.description = "Converts the input data to an ordinal integer array.
e.g. Hello
becomes 72 101 108 108 111
";
+ this.inputType = "byteArray";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {byteArray} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0]);
+ return input.join(delim);
+ }
+
+}
+
+export default ToDecimal;
diff --git a/src/core/operations/ToHexContent.mjs b/src/core/operations/ToHexContent.mjs
new file mode 100644
index 00000000..af9ae22c
--- /dev/null
+++ b/src/core/operations/ToHexContent.mjs
@@ -0,0 +1,81 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {toHex} from "../lib/Hex";
+
+/**
+ * To Hex Content operation
+ */
+class ToHexContent extends Operation {
+
+ /**
+ * ToHexContent constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "To Hex Content";
+ this.module = "Default";
+ this.description = "Converts special characters in a string to hexadecimal.
e.g. foo=bar
becomes foo|3d|bar
.";
+ this.inputType = "byteArray";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Convert",
+ "type": "option",
+ "value": ["Only special chars", "Only special chars including spaces", "All chars"]
+ },
+ {
+ "name": "Print spaces between bytes",
+ "type": "boolean",
+ "value": false
+ }
+ ];
+ }
+
+ /**
+ * @param {byteArray} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const convert = args[0];
+ const spaces = args[1];
+ if (convert === "All chars") {
+ let result = "|" + toHex(input) + "|";
+ if (!spaces) result = result.replace(/ /g, "");
+ return result;
+ }
+
+ let output = "",
+ inHex = false,
+ b;
+ const convertSpaces = convert === "Only special chars including spaces";
+ for (let i = 0; i < input.length; i++) {
+ b = input[i];
+ if ((b === 32 && convertSpaces) || (b < 48 && b !== 32) || (b > 57 && b < 65) || (b > 90 && b < 97) || b > 122) {
+ if (!inHex) {
+ output += "|";
+ inHex = true;
+ } else if (spaces) output += " ";
+ output += toHex([b]);
+ } else {
+ if (inHex) {
+ output += "|";
+ inHex = false;
+ }
+ output += Utils.chr(input[i]);
+ }
+ }
+ if (inHex) output += "|";
+ return output;
+ }
+
+}
+
+export default ToHexContent;
diff --git a/src/core/operations/ToOctal.mjs b/src/core/operations/ToOctal.mjs
new file mode 100644
index 00000000..7cfb4736
--- /dev/null
+++ b/src/core/operations/ToOctal.mjs
@@ -0,0 +1,49 @@
+/**
+ * @author Matt C [matt@artemisbot.uk]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+
+
+/**
+ * To Octal operation
+ */
+class ToOctal extends Operation {
+
+ /**
+ * ToOctal constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "To Octal";
+ this.module = "Default";
+ this.description = "Converts the input string to octal bytes separated by the specified delimiter.
e.g. The UTF-8 encoded string Γειά σου
becomes 316 223 316 265 316 271 316 254 40 317 203 316 277 317 205
";
+ this.inputType = "byteArray";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Delimiter",
+ "type": "option",
+ "value": DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {byteArray} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+ return input.map(val => val.toString(8)).join(delim);
+ }
+
+}
+
+export default ToOctal;