提供二进制数据转换

This commit is contained in:
宫欣海 2025-03-06 16:00:40 +08:00
parent 32b88f0de8
commit 5e00dd0d25
3 changed files with 269 additions and 1 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "kunpocc", "name": "kunpocc",
"version": "1.0.22", "version": "1.0.23",
"type": "module", "type": "module",
"description": "基于creator3.0+的kunpocc库", "description": "基于creator3.0+的kunpocc库",
"main": "./dist/kunpocc.cjs", "main": "./dist/kunpocc.cjs",

View File

@ -6,6 +6,7 @@ export { Platform, PlatformType } from "./global/Platform";
export { Screen } from "./global/Screen"; export { Screen } from "./global/Screen";
/** tool */ /** tool */
export { Binary } from "./tool/Binary";
export * from "./tool/log"; export * from "./tool/log";
export { MathTool } from "./tool/Math"; export { MathTool } from "./tool/Math";
export { md5 } from "./tool/MD5"; export { md5 } from "./tool/MD5";

267
src/tool/Binary.ts Normal file
View File

@ -0,0 +1,267 @@
/**
* @Author: Gongxh
* @Date: 2025-03-04
* @Description: - 使 JavaScript
*/
export class Binary {
/**
*
*/
public static toBinary(obj: any): Uint8Array {
// console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// console.log("原始数据", JSON.stringify(obj));
const chunks: Uint8Array[] = [];
this.writeValue(obj, chunks);
// 计算总长度
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
const result = new Uint8Array(totalLength);
// 合并所有数据块
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}
// console.log("二进制数据", result);
// console.log("还原数据", JSON.stringify(this.toJson(result)));
return result;
}
/**
* JSON数据
* @param binary
* @returns
*/
public static toJson(binary: any): any {
// 如果是 ArrayBuffer, 转换为 Uint8Array
const uint8Array = binary instanceof ArrayBuffer ? new Uint8Array(binary) : binary;
// 检查是否为二进制格式
if (!this.isBinaryFormat(uint8Array)) {
// 如果不是二进制格式, 直接返回
return binary;
}
const view = new DataView(uint8Array.buffer);
let offset = 0;
return this.readValue(view, offset);
}
/**
*
* @param data
* @returns
*/
public static isBinaryFormat(data: Uint8Array): boolean {
if (!data || !data.length || data.length < 1) {
return false;
}
// 检查第一个字节是否为有效的类型标记0-5
const firstByte = data[0];
if (firstByte < 0 || firstByte > 5) {
return false
}
// 检查数据格式是否符合我们的二进制格式规范
try {
const view = new DataView(data.buffer);
let offset = 0;
// 递归检查数据格式
this.validateBinaryFormat(view, offset);
return true;
} catch (error) {
return false;
}
}
/**
*
* @param view DataView对象
* @param offset
* @returns
*/
private static validateBinaryFormat(view: DataView, offset: number): number {
const type = view.getUint8(offset);
switch (type) {
case 0: // null
return 1;
case 1: // number
return 9;
case 2: { // string
const strLen = view.getUint32(offset + 1, true);
return 5 + strLen;
}
case 3: // boolean
return 2;
case 4: { // array
const arrLen = view.getUint32(offset + 1, true);
let size = 5;
for (let i = 0; i < arrLen; i++) {
size += this.validateBinaryFormat(view, offset + size);
}
return size;
}
case 5: { // object
const objLen = view.getUint32(offset + 1, true);
let size = 5;
for (let i = 0; i < objLen; i++) {
const keyLen = view.getUint32(offset + size, true);
size += 4 + keyLen;
size += this.validateBinaryFormat(view, offset + size);
}
return size;
}
default:
throw new Error('无效的类型标记');
}
}
private static readValue(view: DataView, offset: number): any {
const type = view.getUint8(offset++);
switch (type) {
case 0: // null
return null;
case 1: // number
const num = view.getFloat64(offset, true);
return num;
case 2: { // string
const strLen = view.getUint32(offset, true);
offset += 4;
const strBytes = new Uint8Array(view.buffer, offset, strLen);
return new TextDecoder().decode(strBytes);
}
case 3: // boolean
return view.getUint8(offset) === 1;
case 4: // array
const arrLen = view.getUint32(offset, true);
offset += 4;
const arr = [];
for (let i = 0; i < arrLen; i++) {
arr.push(this.readValue(view, offset));
offset += this.getNextOffset(view, offset);
}
return arr;
case 5: { // object
const objLen = view.getUint32(offset, true);
offset += 4;
const obj: any = {};
for (let i = 0; i < objLen; i++) {
const keyLen = view.getUint32(offset, true);
offset += 4;
let key = '';
for (let j = 0; j < keyLen; j++) {
key += String.fromCharCode(view.getUint8(offset + j));
}
offset += keyLen;
obj[key] = this.readValue(view, offset);
offset += this.getNextOffset(view, offset);
}
return obj;
}
default:
throw new Error(`未知的类型: ${type}`);
}
}
private static writeValue(value: any, chunks: Uint8Array[]): void {
if (value === null) {
chunks.push(new Uint8Array([0]));
return;
}
switch (typeof value) {
case 'number': {
const numBuf = new Uint8Array(9);
numBuf[0] = 1;
const view = new DataView(numBuf.buffer);
view.setFloat64(1, value, true);
chunks.push(numBuf);
break;
}
case 'string': {
const encoder = new TextEncoder();
const strBytes = encoder.encode(value);
const strLen = strBytes.length;
const strBuf = new Uint8Array(5 + strLen);
strBuf[0] = 2;
const view = new DataView(strBuf.buffer);
view.setUint32(1, strLen, true);
strBuf.set(strBytes, 5);
chunks.push(strBuf);
break;
}
case 'boolean': {
const boolBuf = new Uint8Array(2);
boolBuf[0] = 3;
boolBuf[1] = value ? 1 : 0;
chunks.push(boolBuf);
break;
}
case 'object': {
if (Array.isArray(value)) {
const arrBuf = new Uint8Array(5);
arrBuf[0] = 4;
const view = new DataView(arrBuf.buffer);
view.setUint32(1, value.length, true);
chunks.push(arrBuf);
for (const item of value) {
this.writeValue(item, chunks);
}
} else {
const keys = Object.keys(value);
const objBuf = new Uint8Array(5);
objBuf[0] = 5;
const view = new DataView(objBuf.buffer);
view.setUint32(1, keys.length, true);
chunks.push(objBuf);
for (const key of keys) {
const keyLen = key.length;
const keyBuf = new Uint8Array(4 + keyLen);
const keyView = new DataView(keyBuf.buffer);
keyView.setUint32(0, keyLen, true);
const keyBytes = new TextEncoder().encode(key);
keyBuf.set(keyBytes, 4);
chunks.push(keyBuf);
this.writeValue(value[key], chunks);
}
}
break;
}
default:
throw new Error(`不支持的类型: ${typeof value}`);
}
}
private static getNextOffset(view: DataView, offset: number): number {
const type = view.getUint8(offset);
switch (type) {
case 0: return 1; // null
case 1: return 9; // number
case 2: return 5 + view.getUint32(offset + 1, true); // string
case 3: return 2; // boolean
case 4: { // array
const arrLen = view.getUint32(offset + 1, true);
let currentSize = 5;
for (let i = 0; i < arrLen; i++) {
currentSize += this.getNextOffset(view, offset + currentSize);
}
return currentSize;
}
case 5: { // object
const objLen = view.getUint32(offset + 1, true);
let currentSize = 5;
for (let i = 0; i < objLen; i++) {
const keyLen = view.getUint32(offset + currentSize, true);
currentSize += 4 + keyLen;
currentSize += this.getNextOffset(view, offset + currentSize);
}
return currentSize;
}
default:
throw new Error(`未知的类型: ${type}`);
}
}
}