// text-polyfill.ts
// Minimal encode/decode for utf-8, utf-16le, ascii, latin1, windows-1252
const WINDOWS_1252_EXTRA = {
0x80: "€", 0x82: "‚", 0x83: "ƒ", 0x84: "„", 0x85: "…", 0x86: "†",
0x87: "‡", 0x88: "ˆ", 0x89: "‰", 0x8a: "Š", 0x8b: "‹", 0x8c: "Œ",
0x8e: "Ž", 0x91: "‘", 0x92: "’", 0x93: "“", 0x94: "”", 0x95: "•",
0x96: "–", 0x97: "—", 0x98: "˜", 0x99: "™", 0x9a: "š", 0x9b: "›",
0x9c: "œ", 0x9e: "ž", 0x9f: "Ÿ",
};
const WINDOWS_1252_REVERSE = {};
for (const [code, char] of Object.entries(WINDOWS_1252_EXTRA)) {
WINDOWS_1252_REVERSE[char] = Number.parseInt(code);
}
/**
* Decode text from binary data
* @param bytes Binary data
* @param encoding Encoding
*/
export function textDecode(bytes, encoding = "utf-8") {
switch (encoding.toLowerCase()) {
case "utf-8":
case "utf8":
if (typeof globalThis.TextDecoder !== "undefined") {
return new globalThis.TextDecoder("utf-8").decode(bytes);
}
return decodeUTF8(bytes);
case "utf-16le":
return decodeUTF16LE(bytes);
case "ascii":
return decodeASCII(bytes);
case "latin1":
case "iso-8859-1":
return decodeLatin1(bytes);
case "windows-1252":
return decodeWindows1252(bytes);
default:
throw new RangeError(`Encoding '${encoding}' not supported`);
}
}
export function textEncode(input = "", encoding = "utf-8") {
switch (encoding.toLowerCase()) {
case "utf-8":
case "utf8":
if (typeof globalThis.TextEncoder !== "undefined") {
return new globalThis.TextEncoder().encode(input);
}
return encodeUTF8(input);
case "utf-16le":
return encodeUTF16LE(input);
case "ascii":
return encodeASCII(input);
case "latin1":
case "iso-8859-1":
return encodeLatin1(input);
case "windows-1252":
return encodeWindows1252(input);
default:
throw new RangeError(`Encoding '${encoding}' not supported`);
}
}
// --- Internal helpers ---
function decodeUTF8(bytes) {
let out = "";
let i = 0;
while (i < bytes.length) {
const b1 = bytes[i++];
if (b1 < 0x80) {
out += String.fromCharCode(b1);
}
else if (b1 < 0xe0) {
const b2 = bytes[i++] & 0x3f;
out += String.fromCharCode(((b1 & 0x1f) << 6) | b2);
}
else if (b1 < 0xf0) {
const b2 = bytes[i++] & 0x3f;
const b3 = bytes[i++] & 0x3f;
out += String.fromCharCode(((b1 & 0x0f) << 12) | (b2 << 6) | b3);
}
else {
const b2 = bytes[i++] & 0x3f;
const b3 = bytes[i++] & 0x3f;
const b4 = bytes[i++] & 0x3f;
let cp = ((b1 & 0x07) << 18) |
(b2 << 12) |
(b3 << 6) |
b4;
cp -= 0x10000;
out += String.fromCharCode(0xd800 + ((cp >> 10) & 0x3ff), 0xdc00 + (cp & 0x3ff));
}
}
return out;
}
function decodeUTF16LE(bytes) {
let out = "";
for (let i = 0; i < bytes.length; i += 2) {
out += String.fromCharCode(bytes[i] | (bytes[i + 1] << 8));
}
return out;
}
function decodeASCII(bytes) {
return String.fromCharCode(...bytes.map((b) => b & 0x7f));
}
function decodeLatin1(bytes) {
return String.fromCharCode(...bytes);
}
function decodeWindows1252(bytes) {
let out = "";
for (const b of bytes) {
if (b >= 0x80 && b <= 0x9f && WINDOWS_1252_EXTRA[b]) {
out += WINDOWS_1252_EXTRA[b];
}
else {
out += String.fromCharCode(b);
}
}
return out;
}
function encodeUTF8(str) {
const out = [];
for (let i = 0; i < str.length; i++) {
const cp = str.charCodeAt(i);
if (cp < 0x80) {
out.push(cp);
}
else if (cp < 0x800) {
out.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));
}
else if (cp < 0x10000) {
out.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
}
else {
out.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
}
}
return new Uint8Array(out);
}
function encodeUTF16LE(str) {
const out = new Uint8Array(str.length * 2);
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i);
out[i * 2] = code & 0xff;
out[i * 2 + 1] = code >> 8;
}
return out;
}
function encodeASCII(str) {
return new Uint8Array([...str].map((ch) => ch.charCodeAt(0) & 0x7f));
}
function encodeLatin1(str) {
return new Uint8Array([...str].map((ch) => ch.charCodeAt(0) & 0xff));
}
function encodeWindows1252(str) {
return new Uint8Array([...str].map((ch) => {
const code = ch.charCodeAt(0);
if (code <= 0xff)
return code;
if (WINDOWS_1252_REVERSE[ch] !== undefined)
return WINDOWS_1252_REVERSE[ch];
return 0x3f; // '?'
}));
}