feat(ciphers): add Dancing Men Encode/Decode ops (token-based char(n) format) with Magic detection; add to Encryption/Encoding category
This commit is contained in:
parent
eb684745fe
commit
5f3e9a9624
@ -130,6 +130,8 @@
|
|||||||
"From Morse Code",
|
"From Morse Code",
|
||||||
"Bacon Cipher Encode",
|
"Bacon Cipher Encode",
|
||||||
"Bacon Cipher Decode",
|
"Bacon Cipher Decode",
|
||||||
|
"Dancing Men Encode",
|
||||||
|
"Dancing Men Decode",
|
||||||
"Bifid Cipher Encode",
|
"Bifid Cipher Encode",
|
||||||
"Bifid Cipher Decode",
|
"Bifid Cipher Decode",
|
||||||
"Caesar Box Cipher",
|
"Caesar Box Cipher",
|
||||||
|
|||||||
76
src/core/operations/DancingMenDecode.mjs
Normal file
76
src/core/operations/DancingMenDecode.mjs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* @author Agent Mode
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dancing Men Decode operation
|
||||||
|
*
|
||||||
|
* Decodes textual Dancing Men tokens like char(97)..char(122) back to letters a-z.
|
||||||
|
* If a token is suffixed with '!' (flag), it can be interpreted as a word separator.
|
||||||
|
*/
|
||||||
|
class DancingMenDecode extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DancingMenDecode constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Dancing Men Decode";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "Decode Dancing Men token format (char(97)..char(122), optional ! for flags) back to text.";
|
||||||
|
this.infoURL = "https://www.dcode.fr/dancing-men-cipher";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Flags indicate spaces",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Magic detection: sequence of 3+ char(ddd) tokens optionally with trailing '!'
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^(?:\\s*char\\(\\d{2,3}\\)!?\\s*){3,}$",
|
||||||
|
args: [false],
|
||||||
|
useful: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [flagsAsSpaces] = args;
|
||||||
|
const tokenRe = /char\((\d{2,3})\)(!?)/g;
|
||||||
|
let out = "";
|
||||||
|
let lastIndex = 0;
|
||||||
|
let m;
|
||||||
|
while ((m = tokenRe.exec(input)) !== null) {
|
||||||
|
// Append any intermediary non-token text unchanged
|
||||||
|
if (m.index > lastIndex) {
|
||||||
|
out += input.slice(lastIndex, m.index);
|
||||||
|
}
|
||||||
|
const code = parseInt(m[1], 10);
|
||||||
|
let ch = "";
|
||||||
|
if (code >= 97 && code <= 122) ch = String.fromCharCode(code);
|
||||||
|
else if (code >= 65 && code <= 90) ch = String.fromCharCode(code).toLowerCase();
|
||||||
|
else ch = ""; // Unknown token range -> drop
|
||||||
|
out += ch;
|
||||||
|
if (flagsAsSpaces && m[2] === "!") out += " ";
|
||||||
|
lastIndex = tokenRe.lastIndex;
|
||||||
|
}
|
||||||
|
// Append any remainder
|
||||||
|
if (lastIndex < input.length) out += input.slice(lastIndex);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DancingMenDecode;
|
||||||
97
src/core/operations/DancingMenEncode.mjs
Normal file
97
src/core/operations/DancingMenEncode.mjs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* @author Agent Mode
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dancing Men Encode operation
|
||||||
|
*
|
||||||
|
* Encodes Latin letters a-z into textual Dancing Men tokens of the form char(97)..char(122).
|
||||||
|
* Optionally, spaces can be represented by a flag marker appended to the previous token ("!")
|
||||||
|
* to mimic the word-separator flag described in Conan Doyle's short story.
|
||||||
|
*/
|
||||||
|
class DancingMenEncode extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DancingMenEncode constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Dancing Men Encode";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "Encode plaintext to Dancing Men token format using tokens like char(97)..char(122). Optionally mark word boundaries with a flag (!).";
|
||||||
|
this.infoURL = "https://www.dcode.fr/dancing-men-cipher";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Use flags as word separators",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Separator between tokens",
|
||||||
|
type: "option",
|
||||||
|
value: ["Space", "None"],
|
||||||
|
defaultIndex: 0
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [useFlags, sepChoice] = args;
|
||||||
|
const sep = sepChoice === "None" ? "" : " ";
|
||||||
|
|
||||||
|
const out = [];
|
||||||
|
let prevIdx = -1;
|
||||||
|
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
const ch = input[i];
|
||||||
|
const code = ch.toLowerCase().charCodeAt(0);
|
||||||
|
if (code >= 97 && code <= 122) {
|
||||||
|
out.push(`char(${code})`);
|
||||||
|
prevIdx = out.length - 1;
|
||||||
|
} else if (ch === " ") {
|
||||||
|
if (useFlags && prevIdx >= 0) {
|
||||||
|
// Append a flag marker to the previous token to denote word boundary
|
||||||
|
out[prevIdx] = out[prevIdx] + "!";
|
||||||
|
} else {
|
||||||
|
// Represent space explicitly in the stream
|
||||||
|
out.push(" ");
|
||||||
|
prevIdx = -1;
|
||||||
|
}
|
||||||
|
} else if (ch === "\n" || ch === "\r" || ch === "\t") {
|
||||||
|
out.push(ch);
|
||||||
|
prevIdx = -1;
|
||||||
|
} else {
|
||||||
|
// Pass-through other characters as-is
|
||||||
|
out.push(ch);
|
||||||
|
prevIdx = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join but preserve already injected spaces/newlines
|
||||||
|
// We only join char(...) tokens using the chosen separator
|
||||||
|
// Build final by inserting sep between adjacent char(...) tokens (and their optional !)
|
||||||
|
const tokens = [];
|
||||||
|
for (let i = 0; i < out.length; i++) {
|
||||||
|
const cur = out[i];
|
||||||
|
tokens.push(cur);
|
||||||
|
const curIsToken = /^char\(\d{2,3}\)!?$/.test(cur);
|
||||||
|
const next = out[i + 1];
|
||||||
|
const nextIsToken = typeof next === "string" && /^char\(\d{2,3}\)!?$/.test(next);
|
||||||
|
if (sep && curIsToken && nextIsToken) tokens.push(sep);
|
||||||
|
}
|
||||||
|
return tokens.join("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DancingMenEncode;
|
||||||
Loading…
x
Reference in New Issue
Block a user