From 093392be0d99eb3b9ed40beac60d0ef8f206ad48 Mon Sep 17 00:00:00 2001 From: yutent Date: Wed, 29 May 2024 18:49:31 +0800 Subject: [PATCH] init --- .gitignore | 15 ++++ .npmignore | 4 + .prettierrc.yaml | 11 +++ src/base64.js | 28 +++++++ src/helper.js | 47 +++++++++++ src/index.js | 198 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 303 insertions(+) create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 .prettierrc.yaml create mode 100644 src/base64.js create mode 100644 src/helper.js create mode 100644 src/index.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb6b44c --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +dist +node_modules +index.html +.httpserver + +package-lock.json + +._* + +.Spotlight-V100 +.Trashes +.DS_Store +.AppleDouble +.LSOverride + diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..f128c19 --- /dev/null +++ b/.npmignore @@ -0,0 +1,4 @@ +src/ +test/ +build.js +.prettierrc.yaml \ No newline at end of file diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000..6734234 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,11 @@ + +jsxBracketSameLine: true +jsxSingleQuote: true +semi: false +singleQuote: true +printWidth: 80 +useTabs: false +tabWidth: 2 +trailingComma: none +bracketSpacing: true +arrowParens: avoid diff --git a/src/base64.js b/src/base64.js new file mode 100644 index 0000000..6d5ee63 --- /dev/null +++ b/src/base64.js @@ -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)) +} diff --git a/src/helper.js b/src/helper.js new file mode 100644 index 0000000..5c62c01 --- /dev/null +++ b/src/helper.js @@ -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) +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..a886072 --- /dev/null +++ b/src/index.js @@ -0,0 +1,198 @@ +/** + * Buffer对象的 polyfill + * @author yutent + * @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 + } +}