mirror of
https://github.com/Eugeny/tabby.git
synced 2024-11-25 08:33:27 +03:00
247 lines
7.9 KiB
TypeScript
247 lines
7.9 KiB
TypeScript
/* 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
|
|
}
|
|
|
|
import { Buffer } from 'buffer'
|
|
|
|
Buffer.prototype['latin1Slice'] = latin1Slice
|
|
Buffer.prototype['utf8Slice'] = utf8Slice
|
|
Buffer.prototype['base64Slice'] = base64Slice
|
|
Buffer.prototype['utf8Write'] = utf8Write
|
|
Buffer.prototype['hexSlice'] = hexSlice
|
|
|
|
window['Buffer'] = Buffer
|