Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

jce

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jce - npm Package Compare versions

Comparing version
0.1.7
to
0.2.0
+166
-251
jce.js
"use strict";
/**
* @typedef Readable
*/
const Readable = require("stream").Readable;
class JceError extends Error {};
class JceError extends Error { }
const BUF0 = Buffer.alloc(0);
/**
* @typedef {Object} JceStruct jce data struct
* K是字段名(String),V是tag值(UInt8)
* @typedef {{[k: string]: number}} JceStruct jce data struct
*/

@@ -36,20 +32,19 @@

const FLAG_STRUCT_END = Symbol("FLAG_STRUCT_END");
let _encoding = "utf8";
class Struct extends null { }
/**
* @param {Readable} stream
* @returns {Object} {tag: UInt8, type: UInt8, raw: Buffer}
*/
function readHead(stream, return_raw = false) {
let raw = stream.read(1);
const head = raw.readUInt8();
function readHead(stream) {
const head = stream.read(1).readUInt8();
const type = head & 0xf;
let tag = (head & 0xf0) >> 4;
if (tag === 0xf) {
tag = stream.read(1);
if (return_raw)
raw = Buffer.concat([raw, tag]);
tag = tag.readUInt8();
tag = stream.read(1).readUInt8();
}
return {tag, type, raw};
return {tag, type};
}

@@ -59,57 +54,56 @@

* @param {Readable} stream
* @param {Number} type UInt8 0~13
* @returns {any}
* @param {number} type UInt8 0~13
*/
function readBody(stream, type) {
var len;
let len;
switch(type) {
case TYPE_INT8:
return stream.read(1).readInt8();
case TYPE_INT16:
return stream.read(2).readInt16BE();
case TYPE_INT32:
return stream.read(4).readInt32BE();
case TYPE_INT64:
var value = stream.read(8).readBigInt64BE();
if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER)
value = parseInt(value);
return value;
case TYPE_FLOAT:
return stream.read(4).readFloatBE();
case TYPE_DOUBLE:
return stream.read(8).readDoubleBE();
case TYPE_STRING1:
len = stream.read(1).readUInt8();
return len > 0 ? stream.read(len).toString(_encoding) : "";
case TYPE_STRING4:
len = stream.read(4).readUInt32BE();
return len > 0 ? stream.read(len).toString(_encoding) : "";
case TYPE_MAP:
len = readElement(stream).value;
const map = {};
while(len > 0) {
map[readElement(stream).value.toString(_encoding)] = readElement(stream).value;
--len;
}
return map;
case TYPE_LIST:
len = readElement(stream).value;
const list = [];
while(len > 0) {
list.push(readElement(stream).value);
--len;
}
return list;
case TYPE_STRUCT_BEGIN:
return Buffer.alloc(0);
case TYPE_STRUCT_END:
return Buffer.alloc(0);
case TYPE_ZERO:
return 0;
case TYPE_SIMPLE_LIST:
readHead(stream);
len = readElement(stream).value;
return len > 0 ? stream.read(len) : BUF0;
default:
throw new JceError("unknown jce type: " + type)
case TYPE_ZERO:
return 0;
case TYPE_INT8:
return stream.read(1).readInt8();
case TYPE_INT16:
return stream.read(2).readInt16BE();
case TYPE_INT32:
return stream.read(4).readInt32BE();
case TYPE_INT64:
let value = stream.read(8).readBigInt64BE();
if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER)
value = Number(value);
return value;
case TYPE_STRING1:
len = stream.read(1).readUInt8();
return len > 0 ? stream.read(len).toString(_encoding) : "";
case TYPE_STRING4:
len = stream.read(4).readUInt32BE();
return len > 0 ? stream.read(len).toString(_encoding) : "";
case TYPE_SIMPLE_LIST:
readHead(stream);
len = readElement(stream).value;
return len > 0 ? stream.read(len) : BUF0;
case TYPE_LIST:
len = readElement(stream).value;
const list = [];
while(len > 0) {
list.push(readElement(stream).value);
--len;
}
return list;
case TYPE_MAP:
len = readElement(stream).value;
const map = Object.create(null);
while(len > 0) {
map[readElement(stream).value.toString(_encoding)] = readElement(stream).value;
--len;
}
return map;
case TYPE_STRUCT_BEGIN:
return readStruct(stream);
case TYPE_STRUCT_END:
return FLAG_STRUCT_END;
case TYPE_FLOAT:
return stream.read(4).readFloatBE();
case TYPE_DOUBLE:
return stream.read(8).readDoubleBE();
default:
throw new JceError("unknown jce type: " + type);
}

@@ -120,74 +114,13 @@ }

* @param {Readable} stream
* @param {Number} type UInt8 0~13
* @returns {Buffer}
*/
function skipField(stream, type) {
const chunk = [];
var len, l;
switch (type) {
case TYPE_INT8:
chunk.push(stream.read(1));
break;
case TYPE_INT16:
chunk.push(stream.read(2));
break;
case TYPE_INT32:
case TYPE_FLOAT:
chunk.push(stream.read(4));
break;
case TYPE_INT64:
case TYPE_DOUBLE:
chunk.push(stream.read(8));
break;
case TYPE_STRING1:
len = stream.read(1);
chunk.push(len);
l = len.readUInt8();
chunk.push(l>0?stream.read(l):BUF0);
break;
case TYPE_STRING4:
len = stream.read(4);
chunk.push(len);
l = len.readUInt32BE();
chunk.push(l>0?stream.read(l):BUF0);
break;
case TYPE_LIST:
case TYPE_MAP:
case TYPE_STRUCT_BEGIN:
case TYPE_STRUCT_END:
case TYPE_ZERO:
break;
case TYPE_SIMPLE_LIST:
chunk.push(stream.read(1));
const {type, raw} = readHead(stream, true);
chunk.push(raw);
len = readBody(stream, type);
chunk.push(createBody(type, len));
chunk.push(len>0?stream.read(len):BUF0);
break;
}
return Buffer.concat(chunk);
}
/**
* @param {Readable} stream
* @returns {Buffer}
*/
function skipStruct(stream) {
const chunks = [];
let nested_struct_num = 0;
function readStruct(stream) {
const struct = Object.create(Struct.prototype);
while(stream.readableLength) {
const {type, raw} = readHead(stream, true);
if (type === TYPE_STRUCT_BEGIN) {
++nested_struct_num;
const {tag, value} = readElement(stream);
if (value === FLAG_STRUCT_END) {
return struct;
} else {
struct[tag] = value;
}
if (type === TYPE_STRUCT_END) {
--nested_struct_num;
if (nested_struct_num < 0)
break;
}
chunks.push(raw);
chunks.push(skipField(stream, type));
}
return Buffer.concat(chunks);
}

@@ -197,12 +130,6 @@

* @param {Readable} stream
* @returns {Object} {tag: UInt8, value: any}
*/
function readElement(stream) {
var value;
const head = readHead(stream);
if (head.type === TYPE_STRUCT_BEGIN) {
value = skipStruct(stream);
} else {
value = readBody(stream, head.type);
}
const value = readBody(stream, head.type);
return {

@@ -232,3 +159,3 @@ tag: head.tag, value

} else {
throw new JceError("Tag must be less than 256")
throw new JceError("Tag must be less than 256");
}

@@ -245,53 +172,53 @@ }

switch (type) {
case TYPE_INT8:
return Buffer.from([parseInt(value)]);
case TYPE_INT16:
body = Buffer.alloc(2);
body.writeInt16BE(parseInt(value));
return body;
case TYPE_INT32:
body = Buffer.alloc(4);
body.writeInt32BE(parseInt(value));
return body;
case TYPE_INT64:
body = Buffer.alloc(8);
body.writeBigInt64BE(BigInt(value));
return body;
case TYPE_FLOAT:
body = Buffer.alloc(4);
body.writeFloatBE(value);
return body;
case TYPE_DOUBLE:
body = Buffer.alloc(8);
body.writeDoubleBE(value);
return body;
case TYPE_STRING1:
len = Buffer.from([value.length]);
return Buffer.concat([len, Buffer.from(value)]);
case TYPE_STRING4:
len = Buffer.alloc(4);
len.writeUInt32BE(value.length);
return Buffer.concat([len, Buffer.from(value)]);
case TYPE_MAP:
body = [];
let n = 0;
for (let k of Object.keys(value)) {
++n;
body.push(createElement(TAG_MAP_K, k));
body.push(createElement(TAG_MAP_V, value[k]));
}
body.unshift(createElement(TAG_LENGTH, n));
return Buffer.concat(body);
case TYPE_LIST:
body = [createElement(TAG_LENGTH, value.length)];
for (let i = 0; i < value.length; ++i) {
body.push(createElement(TAG_LIST_E, value[i]));
}
return Buffer.concat(body);
// case TYPE_STRUCT_BEGIN:
// case TYPE_STRUCT_END:
case TYPE_ZERO:
return Buffer.alloc(0);
case TYPE_SIMPLE_LIST:
return Buffer.concat([createHead(0, TAG_BYTES), createElement(TAG_LENGTH, value.length), value]);
case TYPE_INT8:
return Buffer.from([parseInt(value)]);
case TYPE_INT16:
body = Buffer.alloc(2);
body.writeInt16BE(parseInt(value));
return body;
case TYPE_INT32:
body = Buffer.alloc(4);
body.writeInt32BE(parseInt(value));
return body;
case TYPE_INT64:
body = Buffer.alloc(8);
body.writeBigInt64BE(BigInt(value));
return body;
case TYPE_FLOAT:
body = Buffer.alloc(4);
body.writeFloatBE(value);
return body;
case TYPE_DOUBLE:
body = Buffer.alloc(8);
body.writeDoubleBE(value);
return body;
case TYPE_STRING1:
len = Buffer.from([value.length]);
return Buffer.concat([len, Buffer.from(value)]);
case TYPE_STRING4:
len = Buffer.alloc(4);
len.writeUInt32BE(value.length);
return Buffer.concat([len, Buffer.from(value)]);
case TYPE_MAP:
body = [];
let n = 0;
for (let k of Object.keys(value)) {
++n;
body.push(createElement(TAG_MAP_K, k));
body.push(createElement(TAG_MAP_V, value[k]));
}
body.unshift(createElement(TAG_LENGTH, n));
return Buffer.concat(body);
case TYPE_LIST:
body = [createElement(TAG_LENGTH, value.length)];
for (let i = 0; i < value.length; ++i) {
body.push(createElement(TAG_LIST_E, value[i]));
}
return Buffer.concat(body);
// case TYPE_STRUCT_BEGIN:
// case TYPE_STRUCT_END:
case TYPE_ZERO:
return Buffer.alloc(0);
case TYPE_SIMPLE_LIST:
return Buffer.concat([createHead(0, TAG_BYTES), createElement(TAG_LENGTH, value.length), value]);
}

@@ -313,35 +240,35 @@ }

switch (type) {
case "string":
value = Buffer.from(value, _encoding);
type = value.length <= 0xff ? TYPE_STRING1 : TYPE_STRING4;
break;
case "object":
if (value === null)
throw new JceError("Unsupported type: null");
if (value instanceof Buffer || value instanceof Uint8Array || value instanceof ArrayBuffer)
type = TYPE_SIMPLE_LIST;
case "string":
value = Buffer.from(value, _encoding);
type = value.length <= 0xff ? TYPE_STRING1 : TYPE_STRING4;
break;
case "object":
if (value === null)
throw new JceError("Unsupported type: null");
if (value instanceof Buffer || value instanceof Uint8Array || value instanceof ArrayBuffer)
type = TYPE_SIMPLE_LIST;
else
type = Array.isArray(value) ? TYPE_LIST : TYPE_MAP;
break;
case "bigint":
case "number":
if (value == 0)
type = TYPE_ZERO;
else if (Number.isInteger(value) || type === "bigint") {
if (value >= -0x80 && value <= 0x7f)
type = TYPE_INT8;
else if (value >= -0x8000 && value <= 0x7fff)
type = TYPE_INT16;
else if (value >= -0x80000000 && value <= 0x7fffffff)
type = TYPE_INT32;
else if (value >= -0x8000000000000000n && value <= 0x7fffffffffffffffn)
type = TYPE_INT64;
else
type = Array.isArray(value) ? TYPE_LIST : TYPE_MAP;
break;
case "bigint":
case "number":
if (value == 0)
type = TYPE_ZERO;
else if (Number.isInteger(value) || type === "bigint") {
if (value >= -0x80 && value <= 0x7f)
type = TYPE_INT8;
else if (value >= -0x8000 && value <= 0x7fff)
type = TYPE_INT16;
else if (value >= -0x80000000 && value <= 0x7fffffff)
type = TYPE_INT32;
else if (value >= -0x8000000000000000n && value <= 0x7fffffffffffffffn)
type = TYPE_INT64;
else
throw new JceError("Unsupported integer range: " + value);
} else {
type = TYPE_DOUBLE; //we don't use float
}
break;
default:
throw new JceError("Unsupported type: " + type);
throw new JceError("Unsupported integer range: " + value);
} else {
type = TYPE_DOUBLE; //we don't use float
}
break;
default:
throw new JceError("Unsupported type: " + type);
}

@@ -357,5 +284,3 @@ const head = createHead(type, tag);

* 设置字符串编码
* @see https://nodejs.org/dist/latest/docs/api/buffer.html#buffer_buffers_and_character_encodings
* @param {String} encoding
* @returns {void}
* @param {BufferEncoding} encoding
*/

@@ -368,20 +293,12 @@ function setEncoding(encoding = "utf8") {

* 调用此函数进行jce解码
* 嵌套结构会跳过并返回此段buffer,需要再次decode
* @param {Buffer} blob
* @param {JceStruct|undefined} struct undefined时tag作为键返回
* @returns {Object} 键值对
* @returns {{[k: number]: any}}
*/
function decode(blob, struct = undefined) {
function decode(blob) {
const stream = Readable.from(blob, {objectMode: false});
stream.read(0);
const result = {};
const result = Object.create(null);
while(stream.readableLength) {
const {tag, value} = readElement(stream, struct);
if (struct) {
const name = Object.keys(struct).find((v)=>struct[v]===tag);
if (name)
result[name] = value;
} else {
result[tag] = value;
}
const {tag, value} = readElement(stream);
result[tag] = value;
}

@@ -393,5 +310,4 @@ return result;

* 调用此函数进行jce编码
* @param {Object|Array} object 键值对或数组(值为null或undefined自动跳过此tag)
* @param {JceStruct|undefined} struct undefined时取object的键为tag
* @returns {Buffer}
* @param {{[k: number]: any}|any[]} object 键值对或数组(值为null或undefined自动跳过此tag)
* @param {JceStruct} struct undefined时取object的键为tag
*/

@@ -416,3 +332,3 @@ function encode(object, struct = undefined) {

for (const name of Object.keys(struct)) {
if (!object.hasOwnProperty(name))
if (!Reflect.has(object, name))
continue;

@@ -427,7 +343,6 @@ elements.push(createElement(struct[name], object[name]));

* 嵌套结构数据必须调用此函数创建,暂不支持在struct中直接定义
* @param {Object|Array} object
* @param {JceStruct|undefined} struct
* @returns {Nested}
* @param {{[k: number]: any}|any[]} object
* @param {JceStruct} struct
*/
function encodeNested(object, struct) {
function encodeNested(object, struct = undefined) {
return new Nested(encode(object, struct));

@@ -437,3 +352,3 @@ }

module.exports = {
setEncoding, decode, encode, encodeNested
setEncoding, decode, encode, encodeNested, Struct, Nested
};
{
"name": "jce",
"version": "0.1.7",
"version": "0.2.0",
"description": "JCE reader and writer for JavaScript",

@@ -5,0 +5,0 @@ "main": "jce.js",

@@ -47,3 +47,3 @@ # **jce**

const encoded = jce.encode(object, struct);
const decoded = jce.decode(encoded, struct);
const decoded = jce.decode(encoded);
```

@@ -50,0 +50,0 @@

+12
-10

@@ -40,2 +40,4 @@ "use strict";

var encoded, decoded, encoded_nested, decoded_nested;
console.time();

@@ -48,4 +50,4 @@ for (let i = 0; i < 1; ++i) {

// jce.setEncoding("raw");
decoded = jce.decode(encoded, struct);
decoded_nested = jce.decode(decoded.yhn, struct_nested);
decoded = jce.decode(encoded);
// decoded_nested = jce.decode(decoded.yhn, struct_nested);
}

@@ -58,10 +60,10 @@ console.timeEnd();

const encoded_arr = jce.encode([0,1,2,"abc",null,undefined,3.3,{a:1},[666,Buffer.from("qaz")]])
const decoded_arr = jce.decode(encoded_arr)
console.log(encoded_arr)
console.log(decoded_arr)
// const encoded_arr = jce.encode([0,1,2,"abc",null,undefined,3.3,{a:1},[666,Buffer.from("qaz")]])
// const decoded_arr = jce.decode(encoded_arr)
// console.log(encoded_arr)
// console.log(decoded_arr)
const encoded_map = jce.encode({0:1,3:"abc",5:[1,2,3]})
const decoded_map = jce.decode(encoded_map)
console.log(encoded_map)
console.log(decoded_map)
// const encoded_map = jce.encode({0:1,3:"abc",5:[1,2,3]})
// const decoded_map = jce.decode(encoded_map)
// console.log(encoded_map)
// console.log(decoded_map)