master
yutent 2024-05-29 18:49:31 +08:00
commit 093392be0d
6 changed files with 303 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
dist
node_modules
index.html
.httpserver
package-lock.json
._*
.Spotlight-V100
.Trashes
.DS_Store
.AppleDouble
.LSOverride

4
.npmignore Normal file
View File

@ -0,0 +1,4 @@
src/
test/
build.js
.prettierrc.yaml

11
.prettierrc.yaml Normal file
View File

@ -0,0 +1,11 @@
jsxBracketSameLine: true
jsxSingleQuote: true
semi: false
singleQuote: true
printWidth: 80
useTabs: false
tabWidth: 2
trailingComma: none
bracketSpacing: true
arrowParens: avoid

28
src/base64.js Normal file
View File

@ -0,0 +1,28 @@
import { encode, decode } from './helper.js'
// string 转 binary
export function str2bin(str) {
let bin = ''
let u8 = encode(str) // 转成Uint8Array
for (let i = 0; i < u8.length; i++) {
bin += String.fromCharCode(u8[i])
}
return bin
}
export function bin2str(b) {
let u8 = new Uint8Array(b.length)
for (let i = 0; i < u8.length; i++) {
u8[i] = b[i].charCodeAt(0)
}
return decode(u8)
}
// 支持对中文的base64编码
export function base64encode(str) {
return btoa(str2bin(str))
}
export function base64decode(str) {
return bin2str(atob(str))
}

47
src/helper.js Normal file
View File

@ -0,0 +1,47 @@
const encoder = new TextEncoder()
const decoder = new TextDecoder()
/**
* String Uint8Array
*/
export function encode(txt) {
return encoder.encode(txt)
}
/**
* Uint8Array String
*/
export function decode(u8) {
return decoder.decode(u8)
}
export function getType(val) {
return Object.prototype.toString.call(val).slice(8, -1)
}
export function to16(n) {
let p = ''
if (n < 16) {
p = '0'
}
return p + n.toString(16)
}
// 将16进制的文本, 转成uint8array
export function hex2u8(str) {
if (str.length % 2) {
throw new Error('Argument str is not a vaild hex string')
}
let u8 = new Uint8Array(str.length / 2)
for (let i = 0; i <= u8.length; i++) {
u8[i] = parseInt(str.slice(i * 2, i * 2 + 2), 16)
}
return u8
}
/**
* 计算二维数组的总长度
*/
export function sum(list) {
return list.reduce((total, it) => total + it.length, 0)
}

198
src/index.js Normal file
View File

@ -0,0 +1,198 @@
/**
* Buffer对象的 polyfill
* @author yutent<yutent.io@gmail.com>
* @date 2024/05/29 12:29:17
*/
import { encode, decode, getType, to16, hex2u8, sum } from './helper.js'
import { base64encode, base64decode, str2bin, bin2str } from './base64.js'
/**
* 将其他类型的值, 转为uint8array
*/
function any2u8(data = '', encoding = 'utf8') {
if (typeof data === 'object') {
let type = getType(data)
switch (type) {
case 'Buffer':
case 'Uint8Array':
return data
case 'ArrayBuffer':
break
case 'DataView':
data = data.buffer
break
}
return new Uint8Array(data)
} else {
switch (encoding) {
case 'base64':
data = base64decode(data)
break
case 'hex':
return hex2u8(data)
case 'binary':
data = bin2str(data)
break
}
return encode(data + '')
}
}
/**
* 创建基于Uint8Array的Buffer类
*/
export default class Buffer extends Uint8Array {
get [Symbol.toStringTag]() {
return 'Buffer'
}
static from(data, offsetOrEncoding, end) {
let buf = data
let start = 0
let _encoding = 'utf8'
if (offsetOrEncoding !== void 0) {
if (typeof offsetOrEncoding === 'number') {
start = offsetOrEncoding
} else if (typeof offsetOrEncoding === 'string') {
_encoding = offsetOrEncoding
}
}
buf = any2u8(data, _encoding)
return new Buffer(buf.slice(start, end))
}
static alloc(len, str = '', encoding) {
let buf = new Buffer(len)
if (str) {
buf.fill(str, 0, len, encoding)
}
return buf
}
static concat(list, encoding) {
let len = sum(list)
let buf = Buffer.alloc(len)
let offset = 0
for (let it of list) {
it.copy(buf, offset)
offset += it.length
}
return buf
}
static isBuffer(target) {
return getType(target) === 'Buffer'
}
#replace(target, start, end) {
for (let i = 0; i < end - start; i++) {
this[start + i] = target[i]
}
}
toJSON() {
return { type: 'Buffer', data: [...this].map(to16) }
}
/**
* 这个重构为nodejs版的buf.toString()的功能
*/
toString(encoding = 'utf8', start = 0, end) {
let buf = this.slice(start, end)
switch (encoding) {
case 'base64':
return base64encode(buf)
case 'hex':
return [...buf].map(to16).join('')
case 'binary':
return str2bin(decode(buf))
default:
return decode(buf)
}
}
/**
* 原生的 Uint8Array的fill只支持数字,
* 这里拓展, 支持字符串和其他Array对象, 与nodejs版相似
*/
fill(val, start = 0, end, encoding = 'utf8') {
//
end ??= this.length
if (typeof val === 'number') {
super.fill(val, start, end)
} else {
val = [...any2u8(val, encoding)]
if (val.length === 0) {
val = [0]
}
let tmp = val
while (tmp.length < end - start) {
tmp = tmp.concat(val)
}
tmp = tmp.slice(0, end)
this.#replace(tmp, start, end)
}
}
/**
* 向目标对象中复制内容 (改变的是目标对象, 不是自己)
*/
copy(target, targetStart = 0, sourceStart = 0, sourceEnd) {
if (!(target instanceof Buffer)) {
throw new TypeError(
"copy()'s argument target must be a Buffer Object, but got %s",
getType(target)
)
}
sourceEnd ??= this.length
// 复制的总长度, 默认等于总长
let copied = sourceEnd - sourceStart
if (copied > 0) {
target.#replace(
this.slice(sourceStart, sourceEnd),
targetStart,
targetStart + copied
)
}
return copied
}
/**
* 在指定位置, 写入指定内容
*/
write(str = '', offset = 0, len, encoding = 'utf8') {
len ??= this.length
let written = len - offset
let end = offset + written
let u8 = any2u8(str, encoding)
if (u8.length < written) {
written = u8.length
end = offset + written
}
if (written > 0) {
this.#replace(u8, offset, end)
}
return written
}
}