|
| 1 | +// We trust browsers to always have correct TextDecoder / TextEncoder for UTF-16 with ignoreBOM without streaming |
| 2 | + |
| 3 | +import { encode as encodeJS } from './fallback/utf16.js' |
| 4 | +import { isLE, E_STRING, E_STRICT_UNICODE } from './fallback/_utils.js' |
| 5 | + |
| 6 | +const ignoreBOM = true |
| 7 | +const decoderFatalLE = new TextDecoder('utf-16le', { ignoreBOM, fatal: true }) |
| 8 | +const decoderLooseLE = new TextDecoder('utf-16le', { ignoreBOM }) |
| 9 | +const decoderFatalBE = new TextDecoder('utf-16be', { ignoreBOM, fatal: true }) |
| 10 | +const decoderLooseBE = new TextDecoder('utf-16be', { ignoreBOM }) |
| 11 | +const decoderFatal16 = isLE ? decoderFatalLE : decoderFatalBE |
| 12 | +const decoderLoose16 = isLE ? decoderLooseLE : decoderLooseBE |
| 13 | +const { isWellFormed } = String.prototype |
| 14 | + |
| 15 | +function encode(str, loose, format) { |
| 16 | + if (typeof str !== 'string') throw new TypeError(E_STRING) |
| 17 | + if (format !== 'uint16' && format !== 'uint8-le' && format !== 'uint8-be') { |
| 18 | + throw new TypeError('Unknown format') |
| 19 | + } |
| 20 | + |
| 21 | + if (!loose && isWellFormed && !isWellFormed.call(str)) throw new TypeError(E_STRICT_UNICODE) |
| 22 | + const shouldSwap = (isLE && format === 'uint8-be') || (!isLE && format === 'uint8-le') |
| 23 | + const u16 = encodeJS(str, loose, !loose && isWellFormed, shouldSwap) |
| 24 | + return format === 'uint16' ? u16 : new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength) |
| 25 | +} |
| 26 | + |
| 27 | +function decode(input, loose, format) { |
| 28 | + switch (format) { |
| 29 | + case 'uint16': |
| 30 | + if (!(input instanceof Uint16Array)) throw new TypeError('Expected an Uint16Array') |
| 31 | + return loose ? decoderLoose16.decode(input) : decoderFatal16.decode(input) |
| 32 | + case 'uint8-le': |
| 33 | + if (!(input instanceof Uint8Array)) throw new TypeError('Expected an Uint8Array') |
| 34 | + if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes') |
| 35 | + return loose ? decoderLooseLE.decode(input) : decoderFatalLE.decode(input) |
| 36 | + case 'uint8-be': |
| 37 | + if (!(input instanceof Uint8Array)) throw new TypeError('Expected an Uint8Array') |
| 38 | + if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes') |
| 39 | + return loose ? decoderLooseBE.decode(input) : decoderFatalBE.decode(input) |
| 40 | + } |
| 41 | + |
| 42 | + throw new TypeError('Unknown format') |
| 43 | +} |
| 44 | + |
| 45 | +export const utf16fromString = (str, format = 'uint16') => encode(str, false, format) |
| 46 | +export const utf16fromStringLoose = (str, format = 'uint16') => encode(str, true, format) |
| 47 | +export const utf16toString = (arr, format = 'uint16') => decode(arr, false, format) |
| 48 | +export const utf16toStringLoose = (arr, format = 'uint16') => decode(arr, true, format) |
0 commit comments