import { toHexString } from 'src/utils/strings' ; param input param byteOrderMark returns export const utf8Encode = ( input , byteOrderMark = true ) : Uint8Array => { const encoded = [ ] ; if ( byteOrderMark ) encoded . push ( 0xef , 0xbb , 0xbf ) ; for ( let idx = 0 , len = input . length ; idx < len ; ) { const codePoint = input . codePointAt ( idx ) ! ; if ( codePoint < 0x80 ) { const byte1 = codePoint & 0x7f ; encoded . push ( byte1 ) ; idx += 1 ; } else if ( codePoint < 0x0800 ) { const byte1 = ( ( codePoint >> 6 ) & 0x1f ) | 0xc0 ; const byte2 = ( codePoint & 0x3f ) | 0x80 ; encoded . push ( byte1 , byte2 ) ; idx += 1 ; } else if ( codePoint < 0x010000 ) { const byte1 = ( ( codePoint >> 12 ) & 0x0f ) | 0xe0 ; const byte2 = ( ( codePoint >> 6 ) & 0x3f ) | 0x80 ; const byte3 = ( codePoint & 0x3f ) | 0x80 ; encoded . push ( byte1 , byte2 , byte3 ) ; idx += 1 ; } else if ( codePoint < 0x110000 ) { const byte1 = ( ( codePoint >> 18 ) & 0x07 ) | 0xf0 ; const byte2 = ( ( codePoint >> 12 ) & 0x3f ) | 0x80 ; const byte3 = ( ( codePoint >> 6 ) & 0x3f ) | 0x80 ; const byte4 = ( ( codePoint >> 0 ) & 0x3f ) | 0x80 ; encoded . push ( byte1 , byte2 , byte3 , byte4 ) ; idx += 2 ; } else throw new Error ( `Invalid code point: 0x${ toHexString ( codePoint ) }` ) ; } return new Uint8Array ( encoded ) ; } ; param input param byteOrderMark returns export const utf16Encode = ( input , byteOrderMark = true ) : Uint16Array => { const encoded = [ ] ; if ( byteOrderMark ) encoded . push ( 0xfeff ) ; for ( let idx = 0 , len = input . length ; idx < len ; ) { const codePoint = input . codePointAt ( idx ) ! ; if ( codePoint < 0x010000 ) { encoded . push ( codePoint ) ; idx += 1 ; } else if ( codePoint < 0x110000 ) { encoded . push ( highSurrogate ( codePoint ) , lowSurrogate ( codePoint ) ) ; idx += 2 ; } else throw new Error ( `Invalid code point: 0x${ toHexString ( codePoint ) }` ) ; } return new Uint16Array ( encoded ) ; } ; param codePoint export const isWithinBMP = ( codePoint ) => codePoint >= 0 && codePoint <= 0xffff ; param codePoint export const hasSurrogates = ( codePoint ) => codePoint >= 0x010000 && codePoint <= 0x10ffff ; export const highSurrogate = ( codePoint ) => Math . floor ( ( codePoint - 0x10000 ) / 0x400 ) + 0xd800 ; export const lowSurrogate = ( codePoint ) => ( ( codePoint - 0x10000 ) % 0x400 ) + 0xdc00 ; enum ByteOrder { BigEndian = 'BigEndian' , LittleEndian = 'LittleEndian' } const REPLACEMENT = '�' . codePointAt ( 0 ) ! ; param input param byteOrderMark returns export const utf16Decode = ( input , byteOrderMark = true ) : string => { if ( input . length <= 1 ) return String . fromCodePoint ( REPLACEMENT ) ; const byteOrder = byteOrderMark ? readBOM ( input ) : ByteOrder . BigEndian ; let idx = byteOrderMark ? 2 : 0 ; const codePoints = [ ] ; while ( input . length - idx >= 2 ) { const first = decodeValues ( input [ idx ++ ] , input [ idx ++ ] , byteOrder ) ; if ( isHighSurrogate ( first ) ) { if ( input . length - idx < 2 ) { codePoints . push ( REPLACEMENT ) ; } else { const second = decodeValues ( input [ idx ++ ] , input [ idx ++ ] , byteOrder ) ; if ( isLowSurrogate ( second ) ) { codePoints . push ( first , second ) ; } else { codePoints . push ( REPLACEMENT ) ; } } } else if ( isLowSurrogate ( first ) ) { idx += 2 ; codePoints . push ( REPLACEMENT ) ; } else { codePoints . push ( first ) ; } } if ( idx < input . length ) codePoints . push ( REPLACEMENT ) ; return String . fromCodePoint ( ... codePoints ) ; } ; param codePoint const isHighSurrogate = ( codePoint ) => codePoint >= 0xd800 && codePoint <= 0xdbff ; param codePoint const isLowSurrogate = ( codePoint ) => codePoint >= 0xdc00 && codePoint <= 0xdfff ; param first param second param byteOrder const decodeValues = ( first , second , byteOrder ) => { if ( byteOrder === ByteOrder . LittleEndian ) return ( second << 8 ) | first ; if ( byteOrder === ByteOrder . BigEndian ) return ( first << 8 ) | second ; throw new Error ( `Invalid byteOrder: ${ byteOrder }` ) ; } ; param bytes const readBOM = ( bytes ) : ByteOrder => ( hasUtf16BigEndianBOM ( bytes ) ? ByteOrder . BigEndian : hasUtf16LittleEndianBOM ( bytes ) ? ByteOrder . LittleEndian : ByteOrder . BigEndian ) ; const hasUtf16BigEndianBOM = ( bytes ) => bytes [ 0 ] === 0xfe && bytes [ 1 ] === 0xff ; const hasUtf16LittleEndianBOM = ( bytes ) => bytes [ 0 ] === 0xff && bytes [ 1 ] === 0xfe ; export const hasUtf16BOM = ( bytes ) => hasUtf16BigEndianBOM ( bytes ) || hasUtf16LittleEndianBOM ( bytes ) ;