/** * @author Daniel Temkin [http://danieltemkin.com] * @author Thomas Leplus [https://www.leplus.org] * @copyright Crown Copyright 2021 * @license Apache-2.0 */ import Operation from "../Operation.mjs"; /** * ROT8000 operation. */ class ROT8000 extends Operation { /** * ROT8000 constructor */ constructor() { super(); this.name = "ROT8000"; this.module = "Default"; this.description = "The simple Caesar-cypher encryption that replaces each Unicode character with the one 0x8000 places forward or back along the alphabet."; this.infoURL = "https://rot8000.com/info"; this.inputType = "string"; this.outputType = "string"; this.args = []; } /** * @param {byteArray} input * @param {Object[]} args * @returns {byteArray} */ run(input, args) { // Inspired from https://github.com/rottytooth/rot8000/blob/main/rot8000.js // these come from the valid-code-point-transitions.json file generated from the c# proj // this is done bc: 1) don't trust JS's understanging of surrogate pairs and 2) consistency with original rot8000 const validCodePoints = { "33": true, "127": false, "161": true, "5760": false, "5761": true, "8192": false, "8203": true, "8232": false, "8234": true, "8239": false, "8240": true, "8287": false, "8288": true, "12288": false, "12289": true, "55296": false, "57344": true }; const bmpSize = 0x10000; const rotList = {}; // the mapping of char to rotated char const hiddenBlocks = []; let startBlock = 0; for (const key in validCodePoints) { if (Object.prototype.hasOwnProperty.call(validCodePoints, key)) { if (validCodePoints[key] === true) hiddenBlocks.push({ start: startBlock, end: parseInt(key, 10) - 1 }); else startBlock = parseInt(key, 10); } } const validIntList = []; // list of all valid chars let currValid = false; for (let i = 0; i < bmpSize; i++) { if (validCodePoints[i] !== undefined) { currValid = validCodePoints[i]; } if (currValid) validIntList.push(i); } const rotateNum = Object.keys(validIntList).length / 2; // go through every valid char and find its match for (let i = 0; i < validIntList.length; i++) { rotList[String.fromCharCode(validIntList[i])] = String.fromCharCode(validIntList[(i + rotateNum) % (rotateNum * 2)]); } let output = ""; for (let count = 0; count < input.length; count++) { // if it is not in the mappings list, just add it directly (no rotation) if (rotList[input[count]] === undefined) { output += input[count]; continue; } // otherwise, rotate it and add it to the string output += rotList[input[count]]; } return output; } /** * Highlight ROT8000 * * @param {Object[]} pos * @param {number} pos[].start * @param {number} pos[].end * @param {Object[]} args * @returns {Object[]} pos */ highlight(pos, args) { return pos; } /** * Highlight ROT8000 in reverse * * @param {Object[]} pos * @param {number} pos[].start * @param {number} pos[].end * @param {Object[]} args * @returns {Object[]} pos */ highlightReverse(pos, args) { return pos; } } export default ROT8000;