typescript
Version:
TypeScript is a language for application scale JavaScript development
61 lines • 2.16 kB
JavaScript
import { Buffer } from "node:buffer";
const surrogateLeadByte = 0xED;
const surrogateSecondByteMin = 0xA0;
const surrogateSecondByteMax = 0xBF;
const continuationByteMin = 0x80;
const continuationByteMax = 0xBF;
function isWtf8Surrogate(bytes, index) {
return index + 2 < bytes.length
&& bytes[index] === surrogateLeadByte
&& bytes[index + 1] >= surrogateSecondByteMin
&& bytes[index + 1] <= surrogateSecondByteMax
&& bytes[index + 2] >= continuationByteMin
&& bytes[index + 2] <= continuationByteMax;
}
function getSurrogateCodeUnit(bytes, index) {
return 0xD000 | ((bytes[index + 1] & 0x3F) << 6) | (bytes[index + 2] & 0x3F);
}
function hasSurrogateLeadByte(bytes) {
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).indexOf(surrogateLeadByte) >= 0;
}
function toUint8Array(input) {
if (input instanceof Uint8Array) {
return input;
}
if (ArrayBuffer.isView(input)) {
return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
}
return new Uint8Array(input);
}
export class Wtf8Decoder extends TextDecoder {
decode(input, options) {
if (input === undefined) {
return super.decode(input, options);
}
const bytes = toUint8Array(input);
if (!hasSurrogateLeadByte(bytes)) {
return super.decode(bytes, options);
}
const parts = [];
let segmentStart = 0;
for (let i = 0; i < bytes.length; i++) {
if (!isWtf8Surrogate(bytes, i)) {
continue;
}
if (segmentStart < i) {
parts.push(super.decode(bytes.subarray(segmentStart, i), options));
}
parts.push(String.fromCharCode(getSurrogateCodeUnit(bytes, i)));
i += 2;
segmentStart = i + 1;
}
if (segmentStart === 0) {
return super.decode(bytes, options);
}
if (segmentStart < bytes.length) {
parts.push(super.decode(bytes.subarray(segmentStart), options));
}
return parts.join("");
}
}
//# sourceMappingURL=wtf8.js.map