mirror of
https://github.com/elder-plinius/P4RS3LT0NGV3.git
synced 2026-07-12 15:36:32 +02:00
Sync upstream and refine Translate/PromptCraft/Glitch UI
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
// base122 encoding (more efficient than Base64)
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Base122',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
func: function(text) {
|
||||
// Base122 uses UTF-8 bytes and encodes them more efficiently
|
||||
// It uses 7-bit ASCII (0-127) plus some safe 2-byte UTF-8 sequences
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let result = '';
|
||||
|
||||
let i = 0;
|
||||
while (i < bytes.length) {
|
||||
const byte = bytes[i];
|
||||
|
||||
if (byte < 128) {
|
||||
// Single byte ASCII
|
||||
result += String.fromCharCode(byte);
|
||||
i++;
|
||||
} else if (i + 1 < bytes.length) {
|
||||
// Try to encode as 2-byte sequence
|
||||
const b1 = byte;
|
||||
const b2 = bytes[i + 1];
|
||||
|
||||
// Check if it's a valid 2-byte UTF-8 sequence
|
||||
if ((b1 & 0xE0) === 0xC0 && (b2 & 0xC0) === 0x80) {
|
||||
result += String.fromCharCode(b1, b2);
|
||||
i += 2;
|
||||
} else {
|
||||
// Fallback: encode as escaped sequence
|
||||
result += String.fromCharCode(0xC2, 0x80 + (byte - 128));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
// Last byte, encode as escaped
|
||||
result += String.fromCharCode(0xC2, 0x80 + (byte - 128));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
const bytes = [];
|
||||
let i = 0;
|
||||
|
||||
while (i < text.length) {
|
||||
const code = text.charCodeAt(i);
|
||||
|
||||
if (code < 128) {
|
||||
bytes.push(code);
|
||||
i++;
|
||||
} else if (i + 1 < text.length) {
|
||||
// Check for 2-byte sequence
|
||||
const b1 = code;
|
||||
const b2 = text.charCodeAt(i + 1);
|
||||
|
||||
if ((b1 & 0xE0) === 0xC0 && (b2 & 0xC0) === 0x80) {
|
||||
// Extract original byte from escaped sequence
|
||||
if (b1 === 0xC2 && b2 >= 0x80 && b2 < 0xC0) {
|
||||
bytes.push(b2 - 0x80);
|
||||
} else {
|
||||
bytes.push(b1, b2);
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
bytes.push(code);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
bytes.push(code);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[base122]';
|
||||
const result = this.func(text.slice(0, 10));
|
||||
return result.substring(0, 15) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
// Base122 produces text that's mostly ASCII with some UTF-8 sequences
|
||||
// Hard to detect reliably, but check for mix of ASCII and UTF-8
|
||||
const hasAscii = /[\x00-\x7F]/.test(text);
|
||||
const hasUtf8 = /[\xC0-\xFF]/.test(text);
|
||||
return hasAscii && text.length >= 8;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// base36 encoding transform
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Base36',
|
||||
priority: 270,
|
||||
category: 'encoding',
|
||||
alphabet: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
func: function(text) {
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let num = 0n;
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
num = num * 256n + BigInt(bytes[i]);
|
||||
}
|
||||
|
||||
if (num === 0n) return '0';
|
||||
|
||||
let result = '';
|
||||
const base = 36n;
|
||||
while (num > 0n) {
|
||||
result = this.alphabet[Number(num % base)] + result;
|
||||
num = num / base;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
try {
|
||||
let num = 0n;
|
||||
const base = 36n;
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const char = text[i].toUpperCase();
|
||||
const idx = this.alphabet.indexOf(char);
|
||||
if (idx === -1) return text;
|
||||
num = num * base + BigInt(idx);
|
||||
}
|
||||
|
||||
// Convert back to bytes
|
||||
const bytes = [];
|
||||
while (num > 0n) {
|
||||
bytes.unshift(Number(num % 256n));
|
||||
num = num / 256n;
|
||||
}
|
||||
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[base36]';
|
||||
const result = this.func(text.slice(0, 4));
|
||||
return result.substring(0, 12) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
const cleaned = text.trim().replace(/\s/g, '').toUpperCase();
|
||||
return cleaned.length >= 4 && /^[0-9A-Z]+$/.test(cleaned);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// base91 encoding transform
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Base91',
|
||||
priority: 270,
|
||||
category: 'encoding',
|
||||
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"',
|
||||
func: function(text) {
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let num = 0n;
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
num = num * 256n + BigInt(bytes[i]);
|
||||
}
|
||||
|
||||
if (num === 0n) return this.alphabet[0];
|
||||
|
||||
let result = '';
|
||||
const base = 91n;
|
||||
while (num > 0n) {
|
||||
result = this.alphabet[Number(num % base)] + result;
|
||||
num = num / base;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
try {
|
||||
let num = 0n;
|
||||
const base = 91n;
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const idx = this.alphabet.indexOf(text[i]);
|
||||
if (idx === -1) return text;
|
||||
num = num * base + BigInt(idx);
|
||||
}
|
||||
|
||||
// Convert back to bytes
|
||||
const bytes = [];
|
||||
while (num > 0n) {
|
||||
bytes.unshift(Number(num % 256n));
|
||||
num = num / 256n;
|
||||
}
|
||||
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[base91]';
|
||||
const result = this.func(text.slice(0, 4));
|
||||
return result.substring(0, 12) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
const cleaned = text.trim().replace(/\s/g, '');
|
||||
return cleaned.length >= 4 && /^[A-Za-z0-9!#$%&()*+,./:;<=>?@[\]^_`{|}~"]+$/.test(cleaned);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// baudot code / ITA2 encoding (teletype code)
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Baudot Code (ITA2)',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
// Baudot/ITA2 5-bit code (letters and figures shift)
|
||||
letters: {
|
||||
0b00000: ' ', // NULL/blank
|
||||
0b00010: 'E',
|
||||
0b00011: '\n', // Line feed
|
||||
0b00100: 'A',
|
||||
0b00101: ' ',
|
||||
0b00110: 'S',
|
||||
0b00111: 'I',
|
||||
0b01000: 'U',
|
||||
0b01001: '\r', // Carriage return
|
||||
0b01010: 'D',
|
||||
0b01011: 'R',
|
||||
0b01100: 'J',
|
||||
0b01101: 'N',
|
||||
0b01110: 'F',
|
||||
0b01111: 'C',
|
||||
0b10000: 'K',
|
||||
0b10001: 'T',
|
||||
0b10010: 'Z',
|
||||
0b10011: 'L',
|
||||
0b10100: 'W',
|
||||
0b10101: 'H',
|
||||
0b10110: 'Y',
|
||||
0b10111: 'P',
|
||||
0b11000: 'Q',
|
||||
0b11001: 'O',
|
||||
0b11010: 'B',
|
||||
0b11011: 'G',
|
||||
0b11100: 'Figures', // Shift to figures
|
||||
0b11101: 'M',
|
||||
0b11110: 'X',
|
||||
0b11111: 'V',
|
||||
},
|
||||
figures: {
|
||||
0b00000: ' ',
|
||||
0b00010: '3',
|
||||
0b00011: '\n',
|
||||
0b00100: '-',
|
||||
0b00101: ' ',
|
||||
0b00110: '\'',
|
||||
0b00111: '8',
|
||||
0b01000: '7',
|
||||
0b01001: '\r',
|
||||
0b01010: '\u0005', // ENQ
|
||||
0b01011: '4',
|
||||
0b01100: '\'', // Bell
|
||||
0b01101: ',',
|
||||
0b01110: '!',
|
||||
0b01111: ':',
|
||||
0b10000: '(',
|
||||
0b10001: '5',
|
||||
0b10010: '+',
|
||||
0b10011: ')',
|
||||
0b10100: '2',
|
||||
0b10101: '$',
|
||||
0b10110: '6',
|
||||
0b10111: '0',
|
||||
0b11000: '1',
|
||||
0b11001: '9',
|
||||
0b11010: '?',
|
||||
0b11011: '&',
|
||||
0b11100: 'Letters', // Shift to letters
|
||||
0b11101: '.',
|
||||
0b11110: '/',
|
||||
0b11111: '=',
|
||||
},
|
||||
func: function(text) {
|
||||
// Create reverse maps
|
||||
const lettersToCode = {};
|
||||
const figuresToCode = {};
|
||||
for (const [code, char] of Object.entries(this.letters)) {
|
||||
if (char !== 'Figures' && char !== 'Letters') {
|
||||
lettersToCode[char] = parseInt(code);
|
||||
}
|
||||
}
|
||||
for (const [code, char] of Object.entries(this.figures)) {
|
||||
if (char !== 'Figures' && char !== 'Letters') {
|
||||
figuresToCode[char] = parseInt(code);
|
||||
}
|
||||
}
|
||||
|
||||
let result = '';
|
||||
let inFigures = false;
|
||||
|
||||
for (const char of text.toUpperCase()) {
|
||||
// Check if we need to shift
|
||||
const isFigure = /[0-9\-'():!$?&.\/+=]/.test(char);
|
||||
|
||||
if (isFigure && !inFigures) {
|
||||
result += String.fromCharCode(0b11100); // Figures shift
|
||||
inFigures = true;
|
||||
} else if (!isFigure && inFigures) {
|
||||
result += String.fromCharCode(0b11111); // Letters shift (approximate)
|
||||
inFigures = false;
|
||||
}
|
||||
|
||||
// Encode character
|
||||
const code = inFigures ? figuresToCode[char] : lettersToCode[char];
|
||||
if (code !== undefined) {
|
||||
result += String.fromCharCode(code);
|
||||
} else {
|
||||
result += char; // Keep unmapped
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
let result = '';
|
||||
let inFigures = false;
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const code = text.charCodeAt(i) & 0x1F; // 5 bits
|
||||
|
||||
if (code === 0b11100) {
|
||||
inFigures = true;
|
||||
continue;
|
||||
} else if (code === 0b11111) {
|
||||
inFigures = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const map = inFigures ? this.figures : this.letters;
|
||||
const char = map[code];
|
||||
if (char && char !== 'Figures' && char !== 'Letters') {
|
||||
result += char;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[baudot]';
|
||||
return this.func(text.slice(0, 5));
|
||||
},
|
||||
detector: function(text) {
|
||||
// Baudot uses 5-bit codes (0-31)
|
||||
// Check for characters in the 5-bit range
|
||||
const has5Bit = /[\x00-\x1F]/.test(text);
|
||||
return has5Bit && text.length >= 5;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// binary coded decimal (BCD) transform
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Binary Coded Decimal',
|
||||
priority: 300,
|
||||
category: 'encoding',
|
||||
func: function(text) {
|
||||
return [...text].map(c => {
|
||||
const code = c.charCodeAt(0);
|
||||
// Convert each digit of the char code to BCD
|
||||
return code.toString().split('').map(d => {
|
||||
const digit = parseInt(d);
|
||||
return digit.toString(2).padStart(4, '0');
|
||||
}).join(' ');
|
||||
}).join(' ');
|
||||
},
|
||||
reverse: function(text) {
|
||||
try {
|
||||
const bcdGroups = text.trim().split(/\s+/);
|
||||
const chars = [];
|
||||
let currentCode = '';
|
||||
|
||||
for (let i = 0; i < bcdGroups.length; i++) {
|
||||
if (bcdGroups[i].length === 4 && /^[01]+$/.test(bcdGroups[i])) {
|
||||
currentCode += parseInt(bcdGroups[i], 2).toString();
|
||||
if (currentCode.length >= 3) {
|
||||
const code = parseInt(currentCode);
|
||||
if (code >= 0 && code <= 65535) {
|
||||
chars.push(String.fromCharCode(code));
|
||||
currentCode = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chars.join('');
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[bcd]';
|
||||
return this.func(text.slice(0, 2));
|
||||
},
|
||||
detector: function(text) {
|
||||
const cleaned = text.trim().replace(/\s/g, '');
|
||||
return cleaned.length >= 4 && /^[01]+$/.test(cleaned) && cleaned.length % 4 === 0;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
// EBCDIC encoding (IBM character encoding)
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'EBCDIC',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
// EBCDIC to ASCII mapping (simplified - full EBCDIC has many variants)
|
||||
ebcdicToAscii: {
|
||||
0x40: 0x20, // Space
|
||||
0x4A: 0x21, // !
|
||||
0x4B: 0x22, // "
|
||||
0x4C: 0x23, // #
|
||||
0x4D: 0x24, // $
|
||||
0x4E: 0x25, // %
|
||||
0x4F: 0x26, // &
|
||||
0x50: 0x27, // '
|
||||
0x5A: 0x28, // (
|
||||
0x5B: 0x29, // )
|
||||
0x5C: 0x2A, // *
|
||||
0x5D: 0x2B, // +
|
||||
0x5E: 0x2C, // ,
|
||||
0x5F: 0x2D, // -
|
||||
0x60: 0x2E, // .
|
||||
0x61: 0x2F, // /
|
||||
0xF0: 0x30, // 0
|
||||
0xF1: 0x31, // 1
|
||||
0xF2: 0x32, // 2
|
||||
0xF3: 0x33, // 3
|
||||
0xF4: 0x34, // 4
|
||||
0xF5: 0x35, // 5
|
||||
0xF6: 0x36, // 6
|
||||
0xF7: 0x37, // 7
|
||||
0xF8: 0x38, // 8
|
||||
0xF9: 0x39, // 9
|
||||
0x7A: 0x3A, // :
|
||||
0x7B: 0x3B, // ;
|
||||
0x7C: 0x3C, // <
|
||||
0x7D: 0x3D, // =
|
||||
0x7E: 0x3E, // >
|
||||
0x7F: 0x3F, // ?
|
||||
0x81: 0x41, // A
|
||||
0x82: 0x42, // B
|
||||
0x83: 0x43, // C
|
||||
0x84: 0x44, // D
|
||||
0x85: 0x45, // E
|
||||
0x86: 0x46, // F
|
||||
0x87: 0x47, // G
|
||||
0x88: 0x48, // H
|
||||
0x89: 0x49, // I
|
||||
0x91: 0x4A, // J
|
||||
0x92: 0x4B, // K
|
||||
0x93: 0x4C, // L
|
||||
0x94: 0x4D, // M
|
||||
0x95: 0x4E, // N
|
||||
0x96: 0x4F, // O
|
||||
0x97: 0x50, // P
|
||||
0x98: 0x51, // Q
|
||||
0x99: 0x52, // R
|
||||
0xA2: 0x53, // S
|
||||
0xA3: 0x54, // T
|
||||
0xA4: 0x55, // U
|
||||
0xA5: 0x56, // V
|
||||
0xA6: 0x57, // W
|
||||
0xA7: 0x58, // X
|
||||
0xA8: 0x59, // Y
|
||||
0xA9: 0x5A, // Z
|
||||
},
|
||||
func: function(text) {
|
||||
// Convert ASCII to EBCDIC
|
||||
const asciiToEbcdic = {};
|
||||
for (const [ebcdic, ascii] of Object.entries(this.ebcdicToAscii)) {
|
||||
asciiToEbcdic[ascii] = parseInt(ebcdic);
|
||||
}
|
||||
|
||||
let result = '';
|
||||
for (const char of text) {
|
||||
const code = char.charCodeAt(0);
|
||||
// Convert lowercase letters to uppercase before encoding (EBCDIC is uppercase-only)
|
||||
if (code >= 0x61 && code <= 0x7A) { // a-z
|
||||
const upperCode = code - 0x20; // Convert to A-Z
|
||||
if (asciiToEbcdic[upperCode] !== undefined) {
|
||||
result += String.fromCharCode(asciiToEbcdic[upperCode]);
|
||||
} else {
|
||||
result += char; // Keep unmapped characters
|
||||
}
|
||||
} else if (asciiToEbcdic[code] !== undefined) {
|
||||
result += String.fromCharCode(asciiToEbcdic[code]);
|
||||
} else {
|
||||
result += char; // Keep unmapped characters
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
let result = '';
|
||||
for (const char of text) {
|
||||
const code = char.charCodeAt(0);
|
||||
if (this.ebcdicToAscii[code] !== undefined) {
|
||||
result += String.fromCharCode(this.ebcdicToAscii[code]);
|
||||
} else {
|
||||
result += char; // Keep unmapped characters
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[ebcdic]';
|
||||
return this.func(text.slice(0, 8)) + (text.length > 8 ? '...' : '');
|
||||
},
|
||||
detector: function(text) {
|
||||
if (!text || text.length < 2) return false;
|
||||
|
||||
// EBCDIC uses specific byte ranges for letters and numbers
|
||||
// Letters: 0x81-0xA9 (A-Z)
|
||||
// Numbers: 0xF0-0xF9 (0-9)
|
||||
// Punctuation: 0x40-0x7F range
|
||||
|
||||
// Check for EBCDIC-specific character codes (letters and numbers)
|
||||
const hasEbcdicLetters = /[\x81-\x89\x91-\x99\xA2-\xA9]/.test(text); // A-Z in EBCDIC
|
||||
const hasEbcdicNumbers = /[\xF0-\xF9]/.test(text); // 0-9 in EBCDIC
|
||||
|
||||
// Must have at least some EBCDIC-specific characters
|
||||
if (!hasEbcdicLetters && !hasEbcdicNumbers) return false;
|
||||
|
||||
// Reject if text is already readable ASCII (common English words)
|
||||
// This prevents false positives on plain text
|
||||
const commonWords = /\b(the|and|for|are|but|not|you|all|can|her|was|one|our|out|day|get|has|him|his|how|man|new|now|old|see|two|way|who|boy|did|its|let|put|say|she|too|use)\b/i;
|
||||
if (commonWords.test(text)) return false;
|
||||
|
||||
// Check if decoding produces text that looks like it was encoded
|
||||
// EBCDIC-encoded text, when decoded, should have readable ASCII
|
||||
// If the input is already readable ASCII, it's not EBCDIC
|
||||
const readableAscii = /^[\x20-\x7E\s]*$/.test(text);
|
||||
if (readableAscii && !hasEbcdicLetters && !hasEbcdicNumbers) {
|
||||
// If it's all readable ASCII and has no EBCDIC-specific codes, reject
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that at least some characters are in EBCDIC-specific ranges
|
||||
// For short strings, require at least 1 EBCDIC character
|
||||
// For longer strings, require at least 10% to be EBCDIC-specific
|
||||
const ebcdicChars = (text.match(/[\x81-\x89\x91-\x99\xA2-\xA9\xF0-\xF9]/g) || []).length;
|
||||
if (ebcdicChars === 0) return false;
|
||||
|
||||
// For short strings (<= 20 chars), just need at least 1 EBCDIC char
|
||||
if (text.length <= 20) {
|
||||
return ebcdicChars >= 1;
|
||||
}
|
||||
|
||||
// For longer strings, require at least 10% to be EBCDIC-specific
|
||||
const ebcdicRatio = ebcdicChars / text.length;
|
||||
return ebcdicRatio >= 0.1; // At least 10% must be EBCDIC-specific
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// emoji encoding transform
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Emoji Encoding',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
// Map bytes to emoji (using common emojis)
|
||||
emojiMap: [
|
||||
'😀', '😃', '😄', '😁', '😆', '😅', '🤣', '😂', '🙂', '🙃',
|
||||
'😉', '😊', '😇', '🥰', '😍', '🤩', '😘', '😗', '😚', '😙',
|
||||
'😋', '😛', '😜', '🤪', '😝', '🤑', '🤗', '🤭', '🤫', '🤔',
|
||||
'🤐', '🤨', '😐', '😑', '😶', '😏', '😒', '🙄', '😬', '🤥',
|
||||
'😌', '😔', '😪', '🤤', '😴', '😷', '🤒', '🤕', '🤢', '🤮',
|
||||
'🤧', '🥵', '🥶', '😶🌫️', '😵', '😵💫', '🤯', '🤠', '🥳', '😎',
|
||||
'🤓', '🧐', '😕', '😟', '🙁', '😮', '😯', '😲', '😳', '🥺',
|
||||
'😦', '😧', '😨', '😰', '😥', '😢', '😭', '😱', '😖', '😣',
|
||||
'😞', '😓', '😩', '😫', '🥱', '😤', '😡', '😠', '🤬', '😈',
|
||||
'👿', '💀', '☠️', '💩', '🤡', '👹', '👺', '👻', '👽', '👾',
|
||||
'🤖', '😺', '😸', '😹', '😻', '😼', '😽', '🙀', '😿', '😾',
|
||||
'🙈', '🙉', '🙊', '💋', '💌', '💘', '💝', '💖', '💗', '💓',
|
||||
'💞', '💕', '💟', '❣️', '💔', '❤️', '🧡', '💛', '💚', '💙',
|
||||
'💜', '🖤', '🤍', '🤎', '💯', '💢', '💥', '💫', '💦', '💨',
|
||||
'🕳️', '💣', '💬', '👁️🗨️', '🗨️', '🗯️', '💭', '💤', '👋', '🤚',
|
||||
'🖐️', '✋', '🖖', '👌', '🤌', '🤏', '✌️', '🤞', '🤟', '🤘',
|
||||
'🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👍', '👎', '✊',
|
||||
'👊', '🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✍️',
|
||||
'💪', '🦾', '🦿', '🦵', '🦶', '👂', '🦻', '👃', '🧠', '🫀',
|
||||
'🫁', '🦷', '🦴', '👀', '👁️', '👅', '👄', '💋', '🩸', '👶',
|
||||
'🧒', '👦', '👧', '🧑', '👱', '👨', '🧔', '👨🦰', '👨🦱', '👨🦳',
|
||||
'👨🦲', '👩', '👩🦰', '👩🦱', '👩🦳', '👩🦲', '🧓', '👴', '👵', '🙍',
|
||||
'🙎', '🙅', '🙆', '💁', '🙋', '🧏', '🤦', '🤦♂️', '🤦♀️', '🤷',
|
||||
'🤷♂️', '🤷♀️', '🙇', '🙇♂️', '🙇♀️', '🤦', '🤦♂️', '🤦♀️', '🤷', '🤷♂️'
|
||||
],
|
||||
func: function(text) {
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let result = '';
|
||||
|
||||
for (const byte of bytes) {
|
||||
result += this.emojiMap[byte % this.emojiMap.length] + ' ';
|
||||
}
|
||||
|
||||
return result.trim();
|
||||
},
|
||||
reverse: function(text) {
|
||||
// Create reverse map
|
||||
const reverseMap = {};
|
||||
for (let i = 0; i < this.emojiMap.length; i++) {
|
||||
reverseMap[this.emojiMap[i]] = i;
|
||||
}
|
||||
|
||||
// Extract emojis (match any emoji, not just specific range)
|
||||
const emojis = text.match(/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu) || [];
|
||||
const bytes = [];
|
||||
|
||||
for (const emoji of emojis) {
|
||||
if (reverseMap[emoji] !== undefined) {
|
||||
bytes.push(reverseMap[emoji]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[emoji-encoding]';
|
||||
return this.func(text.slice(0, 3));
|
||||
},
|
||||
detector: function(text) {
|
||||
// Check for emoji patterns (broader range)
|
||||
const emojiPattern = /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu;
|
||||
const matches = text.match(emojiPattern) || [];
|
||||
return matches.length >= 3;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// gray code transform
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Gray Code',
|
||||
priority: 300,
|
||||
category: 'encoding',
|
||||
func: function(text) {
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
const binary = Array.from(bytes)
|
||||
.map(b => b.toString(2).padStart(8, '0'))
|
||||
.join('');
|
||||
|
||||
// Convert to Gray code
|
||||
let gray = binary[0];
|
||||
for (let i = 1; i < binary.length; i++) {
|
||||
gray += (parseInt(binary[i - 1]) ^ parseInt(binary[i])).toString();
|
||||
}
|
||||
|
||||
return gray;
|
||||
},
|
||||
reverse: function(text) {
|
||||
try {
|
||||
// Convert from Gray code to binary
|
||||
if (!/^[01]+$/.test(text)) return text;
|
||||
|
||||
let binary = text[0];
|
||||
for (let i = 1; i < text.length; i++) {
|
||||
binary += (parseInt(binary[i - 1]) ^ parseInt(text[i])).toString();
|
||||
}
|
||||
|
||||
// Convert binary to bytes
|
||||
const bytes = [];
|
||||
for (let i = 0; i < binary.length; i += 8) {
|
||||
const byte = binary.slice(i, i + 8);
|
||||
if (byte.length === 8) {
|
||||
bytes.push(parseInt(byte, 2));
|
||||
}
|
||||
}
|
||||
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[gray]';
|
||||
const result = this.func(text.slice(0, 2));
|
||||
return result.substring(0, 16) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
const cleaned = text.trim().replace(/\s/g, '');
|
||||
return cleaned.length >= 8 && /^[01]+$/.test(cleaned);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// quoted-printable encoding transform (RFC 2045)
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Quoted-Printable',
|
||||
priority: 70,
|
||||
category: 'encoding',
|
||||
func: function(text) {
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let result = '';
|
||||
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
const byte = bytes[i];
|
||||
// Printable ASCII (33-126) except = (61) can be used as-is
|
||||
// Space (32) can be used, but often encoded as =20
|
||||
// = (61) must be encoded as =3D
|
||||
if (byte >= 33 && byte <= 60 || byte >= 63 && byte <= 126) {
|
||||
result += String.fromCharCode(byte);
|
||||
} else if (byte === 32) {
|
||||
// Space can be space or =20
|
||||
result += ' ';
|
||||
} else {
|
||||
// Encode as =XX
|
||||
result += '=' + byte.toString(16).toUpperCase().padStart(2, '0');
|
||||
}
|
||||
}
|
||||
|
||||
// Soft line breaks: lines should not exceed 76 chars (excluding CRLF)
|
||||
// For simplicity, we'll add = at end of long lines
|
||||
const lines = [];
|
||||
let currentLine = '';
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
if (currentLine.length >= 75) {
|
||||
lines.push(currentLine + '=');
|
||||
currentLine = result[i];
|
||||
} else {
|
||||
currentLine += result[i];
|
||||
}
|
||||
}
|
||||
if (currentLine) lines.push(currentLine);
|
||||
|
||||
return lines.join('\r\n');
|
||||
},
|
||||
reverse: function(text) {
|
||||
try {
|
||||
// Remove soft line breaks (= at end of line)
|
||||
let cleaned = text.replace(/=\r?\n/g, '').replace(/=\r/g, '');
|
||||
let result = '';
|
||||
|
||||
for (let i = 0; i < cleaned.length; i++) {
|
||||
if (cleaned[i] === '=' && i + 2 < cleaned.length) {
|
||||
const hex = cleaned.substring(i + 1, i + 3);
|
||||
const byte = parseInt(hex, 16);
|
||||
if (!isNaN(byte)) {
|
||||
result += String.fromCharCode(byte);
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result += cleaned[i];
|
||||
}
|
||||
|
||||
return new TextDecoder().decode(new TextEncoder().encode(result));
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[qp]';
|
||||
const result = this.func(text.slice(0, 10));
|
||||
return result.substring(0, 20).replace(/\r?\n/g, ' ') + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
// Check for quoted-printable patterns (=XX hex codes)
|
||||
return /=([0-9A-F]{2})/i.test(text);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// unicode code points encoding transform
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Unicode Code Points',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
func: function(text) {
|
||||
// Encode text as Unicode code points (U+XXXX format)
|
||||
let result = '';
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const code = text.charCodeAt(i);
|
||||
result += 'U+' + code.toString(16).toUpperCase().padStart(4, '0') + ' ';
|
||||
}
|
||||
return result.trim();
|
||||
},
|
||||
reverse: function(text) {
|
||||
// Extract U+XXXX patterns and convert back to characters
|
||||
const matches = text.match(/U\+([0-9A-Fa-f]{4,6})/g) || [];
|
||||
let result = '';
|
||||
for (const match of matches) {
|
||||
const code = parseInt(match.substring(2), 16);
|
||||
if (code >= 0 && code <= 0x10FFFF) {
|
||||
result += String.fromCharCode(code);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[unicode-points]';
|
||||
const result = this.func(text.slice(0, 3));
|
||||
return result.substring(0, 20) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
// Check for U+XXXX pattern
|
||||
const pattern = /U\+[0-9A-Fa-f]{4,6}/;
|
||||
return pattern.test(text) && text.match(/U\+[0-9A-Fa-f]{4,6}/g).length >= 2;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// uuencoding transform (Unix-to-Unix encoding)
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Uuencoding',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
func: function(text) {
|
||||
// Uuencoding encodes 3 bytes into 4 characters
|
||||
// Each character represents 6 bits (0-63)
|
||||
const uuChars = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
|
||||
|
||||
let result = '';
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
|
||||
for (let i = 0; i < bytes.length; i += 3) {
|
||||
const b1 = bytes[i] || 0;
|
||||
const b2 = bytes[i + 1] || 0;
|
||||
const b3 = bytes[i + 2] || 0;
|
||||
|
||||
// Combine 3 bytes (24 bits) into 4 6-bit values
|
||||
const val1 = (b1 >> 2) & 0x3F;
|
||||
const val2 = ((b1 << 4) | (b2 >> 4)) & 0x3F;
|
||||
const val3 = ((b2 << 2) | (b3 >> 6)) & 0x3F;
|
||||
const val4 = b3 & 0x3F;
|
||||
|
||||
result += uuChars[val1] + uuChars[val2] + uuChars[val3] + uuChars[val4];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
const uuChars = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
|
||||
|
||||
const bytes = [];
|
||||
const totalChunks = Math.floor(text.length / 4);
|
||||
|
||||
for (let i = 0; i < totalChunks; i++) {
|
||||
const chunk = text.substring(i * 4, (i + 1) * 4);
|
||||
if (chunk.length < 4) break;
|
||||
|
||||
const val1 = uuChars.indexOf(chunk[0]);
|
||||
const val2 = uuChars.indexOf(chunk[1]);
|
||||
const val3 = uuChars.indexOf(chunk[2]);
|
||||
const val4 = uuChars.indexOf(chunk[3]);
|
||||
|
||||
if (val1 === -1 || val2 === -1 || val3 === -1 || val4 === -1) continue;
|
||||
|
||||
// Reconstruct 3 bytes from 4 6-bit values
|
||||
const b1 = (val1 << 2) | (val2 >> 4);
|
||||
const b2 = ((val2 << 4) | (val3 >> 2)) & 0xFF;
|
||||
const b3 = ((val3 << 6) | val4) & 0xFF;
|
||||
|
||||
bytes.push(b1);
|
||||
bytes.push(b2);
|
||||
bytes.push(b3);
|
||||
}
|
||||
|
||||
// Remove trailing null bytes (padding)
|
||||
while (bytes.length > 0 && bytes[bytes.length - 1] === 0) {
|
||||
bytes.pop();
|
||||
}
|
||||
|
||||
try {
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[uuencoding]';
|
||||
const result = this.func(text.slice(0, 3));
|
||||
return result.substring(0, 8) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
// Uuencoding uses specific character set: space through underscore (ASCII 32-95)
|
||||
const uuPattern = /^[ !"#$%&'()*+,\-./0-9:;<=>?@A-Z[\\\]^_]+$/;
|
||||
return text.length >= 8 && uuPattern.test(text) && text.length % 4 === 0;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// yenc encoding transform (Usenet binary encoding)
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'YEnc',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
func: function(text) {
|
||||
// YEnc encodes bytes by adding 42 (0x2A) and escaping special characters
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let result = '';
|
||||
|
||||
for (const byte of bytes) {
|
||||
let encoded = (byte + 42) % 256;
|
||||
|
||||
// Escape special characters: NULL (0), LF (10), CR (13), = (61)
|
||||
if (encoded === 0 || encoded === 10 || encoded === 13 || encoded === 61) {
|
||||
result += '=' + String.fromCharCode((encoded + 64) % 256);
|
||||
} else {
|
||||
result += String.fromCharCode(encoded);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
const bytes = [];
|
||||
let i = 0;
|
||||
|
||||
while (i < text.length) {
|
||||
if (text[i] === '=' && i + 1 < text.length) {
|
||||
// Escaped character
|
||||
const escaped = text.charCodeAt(i + 1);
|
||||
const decoded = (escaped - 64) % 256;
|
||||
bytes.push((decoded - 42 + 256) % 256);
|
||||
i += 2;
|
||||
} else {
|
||||
// Normal character
|
||||
const encoded = text.charCodeAt(i);
|
||||
bytes.push((encoded - 42 + 256) % 256);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[yenc]';
|
||||
const result = this.func(text.slice(0, 3));
|
||||
return result.substring(0, 8) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
// YEnc produces binary-like data, hard to detect reliably
|
||||
// Check for escape sequences (= followed by character)
|
||||
const escapePattern = /=[\x00-\xFF]/;
|
||||
return escapePattern.test(text) && text.length >= 8;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// z85 encoding (ZeroMQ Base85)
|
||||
import BaseTransformer from '../BaseTransformer.js';
|
||||
|
||||
export default new BaseTransformer({
|
||||
name: 'Z85',
|
||||
priority: 250,
|
||||
category: 'encoding',
|
||||
// Z85 uses a different character set than standard Base85
|
||||
charset: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#',
|
||||
func: function(text) {
|
||||
const bytes = new TextEncoder().encode(text);
|
||||
let result = '';
|
||||
const originalLength = bytes.length;
|
||||
|
||||
// Z85 encodes 4 bytes into 5 characters
|
||||
for (let i = 0; i < bytes.length; i += 4) {
|
||||
const chunk = Array.from(bytes.slice(i, i + 4));
|
||||
const chunkLength = chunk.length;
|
||||
while (chunk.length < 4) chunk.push(0);
|
||||
|
||||
// Convert 4 bytes to 32-bit integer
|
||||
let value = 0;
|
||||
for (let j = 0; j < 4; j++) {
|
||||
value = (value << 8) + chunk[j];
|
||||
}
|
||||
|
||||
// Convert to base 85 (5 digits)
|
||||
const z85Chars = [];
|
||||
for (let j = 0; j < 5; j++) {
|
||||
z85Chars.unshift(this.charset[value % 85]);
|
||||
value = Math.floor(value / 85);
|
||||
}
|
||||
|
||||
result += z85Chars.join('');
|
||||
}
|
||||
|
||||
// Store original length for decoding
|
||||
this._z85OriginalLength = originalLength;
|
||||
|
||||
return result;
|
||||
},
|
||||
reverse: function(text) {
|
||||
const bytes = [];
|
||||
|
||||
// Z85 decodes 5 characters into 4 bytes
|
||||
for (let i = 0; i < text.length; i += 5) {
|
||||
const chunk = text.substring(i, i + 5);
|
||||
if (chunk.length < 5) break;
|
||||
|
||||
// Convert 5 base-85 digits to 32-bit integer
|
||||
let value = 0;
|
||||
for (const char of chunk) {
|
||||
const idx = this.charset.indexOf(char);
|
||||
if (idx === -1) return ''; // Invalid character
|
||||
value = value * 85 + idx;
|
||||
}
|
||||
|
||||
// Extract 4 bytes
|
||||
bytes.push((value >> 24) & 0xFF);
|
||||
bytes.push((value >> 16) & 0xFF);
|
||||
bytes.push((value >> 8) & 0xFF);
|
||||
bytes.push(value & 0xFF);
|
||||
}
|
||||
|
||||
// Trim to original length if we stored it
|
||||
if (this._z85OriginalLength !== undefined) {
|
||||
bytes.length = Math.min(bytes.length, this._z85OriginalLength);
|
||||
} else {
|
||||
// Remove trailing null bytes (padding)
|
||||
while (bytes.length > 0 && bytes[bytes.length - 1] === 0) {
|
||||
bytes.pop();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return new TextDecoder().decode(new Uint8Array(bytes));
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
preview: function(text) {
|
||||
if (!text) return '[z85]';
|
||||
const result = this.func(text.slice(0, 4));
|
||||
return result.substring(0, 10) + '...';
|
||||
},
|
||||
detector: function(text) {
|
||||
// Z85 uses specific character set
|
||||
const z85Pattern = /^[0-9a-zA-Z.\-:+=^!\/\*\?&<>()\[\]{}@%$#]+$/;
|
||||
return text.length >= 5 && z85Pattern.test(text) && text.length % 5 === 0;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user