/* eslint-disable @typescript-eslint/no-unnecessary-condition */ /* eslint-disable @typescript-eslint/init-declarations */ /* eslint-disable prefer-spread */ /* eslint-disable @typescript-eslint/no-invalid-this */ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ // Based on http://stackoverflow.com/a/22747272/680742, the browser with // the lowest limit is Chrome, with 0x10000 args. // We go 1 magnitude less, for safety const MAX_ARGUMENTS_LENGTH = 0x1000 const base64 = require('base64-js') function blitBuffer (src, dst, offset, length) { let i for (i = 0; i < length; ++i) { if (i + offset >= dst.length || i >= src.length) {break} dst[i + offset] = src[i] } return i } export function utf8Write (string, offset, length) { return blitBuffer(utf8ToBytes(string, this.length - offset), this, offset, length) } export function base64Slice (start, end) { if (start === 0 && end === this.length) { return base64.fromByteArray(this) } else { return base64.fromByteArray(this.slice(start, end)) } } function decodeCodePointsArray (codePoints) { const len = codePoints.length if (len <= MAX_ARGUMENTS_LENGTH) { return String.fromCharCode.apply(String, codePoints) // avoid extra slice() } // Decode in chunks to avoid "call stack size exceeded". let res = '' let i = 0 while (i < len) { res += String.fromCharCode.apply( String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) ) } return res } export function latin1Slice (start, end) { let ret = '' end = Math.min(this.length, end) for (let i = start; i < end; ++i) { ret += String.fromCharCode(this[i]) } return ret } export function utf8Slice (this, start, end) { end = Math.min(this.length, end) const res: number[] = [] let i = start while (i < end) { const firstByte = this[i] let codePoint: number|null = null let bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1 if (i + bytesPerSequence <= end) { let secondByte, thirdByte, fourthByte, tempCodePoint switch (bytesPerSequence) { case 1: if (firstByte < 0x80) { codePoint = firstByte } break case 2: secondByte = this[i + 1] if ((secondByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F if (tempCodePoint > 0x7F) { codePoint = tempCodePoint } } break case 3: secondByte = this[i + 1] thirdByte = this[i + 2] if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { codePoint = tempCodePoint } } break case 4: secondByte = this[i + 1] thirdByte = this[i + 2] fourthByte = this[i + 3] if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { codePoint = tempCodePoint } } } } if (codePoint === null) { // we did not generate a valid codePoint so insert a // replacement char (U+FFFD) and advance only 1 byte codePoint = 0xFFFD bytesPerSequence = 1 } else if (codePoint > 0xFFFF) { // encode to utf16 (surrogate pair dance) codePoint -= 0x10000 res.push(codePoint >>> 10 & 0x3FF | 0xD800) codePoint = 0xDC00 | codePoint & 0x3FF } res.push(codePoint) i += bytesPerSequence } return decodeCodePointsArray(res) } function utf8ToBytes (string, units) { units = units || Infinity let codePoint const length = string.length let leadSurrogate = null const bytes: number[] = [] for (let i = 0; i < length; ++i) { codePoint = string.charCodeAt(i) // is surrogate component if (codePoint > 0xD7FF && codePoint < 0xE000) { // last char was a lead if (!leadSurrogate) { // no lead yet if (codePoint > 0xDBFF) { // unexpected trail if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)} continue } else if (i + 1 === length) { // unpaired lead if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)} continue } // valid lead leadSurrogate = codePoint continue } // 2 leads in a row if (codePoint < 0xDC00) { if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)} leadSurrogate = codePoint continue } // valid surrogate pair codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 } else if (leadSurrogate) { // valid bmp char, but last char was a lead if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)} } leadSurrogate = null // encode utf8 if (codePoint < 0x80) { if ((units -= 1) < 0) {break} bytes.push(codePoint) } else if (codePoint < 0x800) { if ((units -= 2) < 0) {break} bytes.push( codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80 ) } else if (codePoint < 0x10000) { if ((units -= 3) < 0) {break} bytes.push( codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ) } else if (codePoint < 0x110000) { if ((units -= 4) < 0) {break} bytes.push( codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ) } else { throw new Error('Invalid code point') } } return bytes } // Create lookup table for `toString('hex')` // See: https://github.com/feross/buffer/issues/219 const hexSliceLookupTable = (function () { const alphabet = '0123456789abcdef' const table = new Array(256) for (let i = 0; i < 16; ++i) { const i16 = i * 16 for (let j = 0; j < 16; ++j) { table[i16 + j] = alphabet[i] + alphabet[j] } } return table })() export function hexSlice (start, end) { const len = this.length if (!start || start < 0) {start = 0} if (!end || end < 0 || end > len) {end = len} let out = '' for (let i = start; i < end; ++i) { out += hexSliceLookupTable[this[i]] } return out }