@alexgyver/bson 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bson.js +156 -41
- package/bson.min.js +1 -1
- package/package.json +1 -1
- package/test.html +30 -1
package/bson.js
CHANGED
|
@@ -1,39 +1,52 @@
|
|
|
1
|
+
const BS_STRING = (0 << 5);
|
|
2
|
+
const BS_BOOLEAN = (1 << 5);
|
|
3
|
+
const BS_INTEGER = (2 << 5);
|
|
4
|
+
const BS_FLOAT = (3 << 5);
|
|
5
|
+
const BS_CODE = (4 << 5);
|
|
6
|
+
const BS_BINARY = (5 << 5);
|
|
7
|
+
const BS_CONTAINER = (6 << 5);
|
|
8
|
+
const BS_NULL = (7 << 5);
|
|
9
|
+
|
|
10
|
+
const BS_CONT_OBJ = (1 << 4);
|
|
11
|
+
const BS_CONT_OPEN = (1 << 3);
|
|
12
|
+
const BS_CONT_ARR = (1 << 2);
|
|
13
|
+
const BS_CONT_CLOSE = (1 << 1);
|
|
14
|
+
|
|
15
|
+
const BS_MAX_LEN = 0b0001111111111111;
|
|
16
|
+
|
|
17
|
+
const BS_TYPE_MASK = 0b11100000;
|
|
18
|
+
const BS_TYPE = x => x & BS_TYPE_MASK;
|
|
19
|
+
const BS_DATA_MASK = 0b00011111;
|
|
20
|
+
const BS_DATA = x => x & BS_DATA_MASK;
|
|
21
|
+
|
|
22
|
+
const BS_BOOLV_MASK = 0b1;
|
|
23
|
+
const BS_BOOLV = x => x & BS_BOOLV_MASK;
|
|
24
|
+
|
|
25
|
+
const BS_NEG_MASK = 0b10000;
|
|
26
|
+
const BS_NEGATIVE = x => x & BS_NEG_MASK;
|
|
27
|
+
const BS_SIZE_MASK = 0b01111;
|
|
28
|
+
const BS_SIZE = x => x & BS_SIZE_MASK;
|
|
29
|
+
|
|
30
|
+
const BS_FLOAT_SIZE = 4;
|
|
31
|
+
const BS_DEC_MASK = 0b1111;
|
|
32
|
+
const BS_DECIMAL = x => x & BS_DEC_MASK;
|
|
33
|
+
|
|
34
|
+
const BS_D16_MSB = x => (x >> 8) & BS_DATA_MASK;
|
|
35
|
+
const BS_D16_LSB = x => x & 0xff;
|
|
36
|
+
const BS_D16_MERGE = (msb5, lsb) => ((msb5 << 8) | lsb) >>> 0;
|
|
37
|
+
|
|
38
|
+
const BS_BIN_PREFIX = "__BSON_BIN_";
|
|
39
|
+
const BS_CODE_PREFIX = "__BSON_CODE_";
|
|
40
|
+
|
|
1
41
|
/**
|
|
2
42
|
* @param {Uint8Array} b
|
|
3
43
|
* @param {Array} codes
|
|
4
44
|
* @returns {Object}
|
|
5
45
|
*/
|
|
6
|
-
export
|
|
46
|
+
export function decodeBson(b, codes = []) {
|
|
7
47
|
if (!b || !(b instanceof Uint8Array)) return null;
|
|
8
48
|
if (!b.length) return {};
|
|
9
49
|
|
|
10
|
-
const BS_STRING = (0 << 5);
|
|
11
|
-
const BS_BOOLEAN = (1 << 5);
|
|
12
|
-
const BS_INTEGER = (2 << 5);
|
|
13
|
-
const BS_FLOAT = (3 << 5);
|
|
14
|
-
const BS_CODE = (4 << 5);
|
|
15
|
-
const BS_BINARY = (5 << 5);
|
|
16
|
-
const BS_CONTAINER = (6 << 5);
|
|
17
|
-
|
|
18
|
-
const BS_CONT_OBJ = (1 << 4);
|
|
19
|
-
const BS_CONT_OPEN = (1 << 3);
|
|
20
|
-
const BS_NEGATIVE = (1 << 4);
|
|
21
|
-
const BS_BIN_PREFIX = "__BSON_BINARY";
|
|
22
|
-
|
|
23
|
-
function unpack5(msb5, lsb) {
|
|
24
|
-
return ((msb5 << 8) | lsb) >>> 0;
|
|
25
|
-
}
|
|
26
|
-
function makeBins(obj, bins) {
|
|
27
|
-
if (typeof obj !== 'object') return;
|
|
28
|
-
for (let k in obj) {
|
|
29
|
-
if (typeof obj[k] === "object" && obj[k] !== null) {
|
|
30
|
-
makeBins(obj[k], bins);
|
|
31
|
-
} else if (typeof obj[k] === "string" && obj[k].startsWith(BS_BIN_PREFIX)) {
|
|
32
|
-
obj[k] = bins[obj[k].split('#')[1]];
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
50
|
let bins = [];
|
|
38
51
|
let stack = [];
|
|
39
52
|
let keyf = true;
|
|
@@ -41,8 +54,8 @@ export default function decodeBson(b, codes = []) {
|
|
|
41
54
|
|
|
42
55
|
try {
|
|
43
56
|
for (let i = 0; i < b.length; i++) {
|
|
44
|
-
const type = b[i]
|
|
45
|
-
const data = b[i]
|
|
57
|
+
const type = BS_TYPE(b[i]);
|
|
58
|
+
const data = BS_DATA(b[i]);
|
|
46
59
|
|
|
47
60
|
switch (type) {
|
|
48
61
|
|
|
@@ -61,18 +74,18 @@ export default function decodeBson(b, codes = []) {
|
|
|
61
74
|
continue;
|
|
62
75
|
|
|
63
76
|
case BS_CODE:
|
|
64
|
-
s += '"' + codes[
|
|
77
|
+
s += '"' + codes[BS_D16_MERGE(data, b[++i])] + '"';
|
|
65
78
|
break;
|
|
66
79
|
|
|
67
80
|
case BS_STRING: {
|
|
68
|
-
let len =
|
|
81
|
+
let len = BS_D16_MERGE(data, b[++i]);
|
|
69
82
|
s += JSON.stringify(new TextDecoder().decode(b.slice(i + 1, i + 1 + len)));
|
|
70
83
|
i += len;
|
|
71
84
|
} break;
|
|
72
85
|
|
|
73
86
|
case BS_INTEGER: {
|
|
74
|
-
if (data
|
|
75
|
-
let len = data
|
|
87
|
+
if (BS_NEGATIVE(data)) s += '-';
|
|
88
|
+
let len = BS_SIZE(data);
|
|
76
89
|
let u8 = new Uint8Array(8);
|
|
77
90
|
u8.set(b.slice(i + 1, i + 1 + len));
|
|
78
91
|
s += new BigUint64Array(u8.buffer)[0];
|
|
@@ -80,19 +93,24 @@ export default function decodeBson(b, codes = []) {
|
|
|
80
93
|
} break;
|
|
81
94
|
|
|
82
95
|
case BS_BOOLEAN:
|
|
83
|
-
s += (data
|
|
96
|
+
s += BS_BOOLV(data) ? 'true' : 'false';
|
|
97
|
+
break;
|
|
98
|
+
|
|
99
|
+
case BS_NULL:
|
|
100
|
+
s += 'null';
|
|
84
101
|
break;
|
|
85
102
|
|
|
86
103
|
case BS_FLOAT: {
|
|
87
|
-
let f = new
|
|
88
|
-
s += (isNaN(f) || !isFinite(f)) ? 'null' : f.toFixed(data);
|
|
89
|
-
i +=
|
|
104
|
+
let f = new DataView(b.buffer, b.byteOffset + i + 1, BS_FLOAT_SIZE).getFloat32(0, true);
|
|
105
|
+
s += (isNaN(f) || !isFinite(f)) ? 'null' : f.toFixed(BS_DECIMAL(data));
|
|
106
|
+
i += BS_FLOAT_SIZE;
|
|
107
|
+
|
|
90
108
|
} break;
|
|
91
109
|
|
|
92
110
|
case BS_BINARY: {
|
|
93
|
-
let len =
|
|
111
|
+
let len = BS_D16_MERGE(data, b[++i]);
|
|
94
112
|
i++;
|
|
95
|
-
s += '"' + BS_BIN_PREFIX +
|
|
113
|
+
s += '"' + BS_BIN_PREFIX + bins.length + '"';
|
|
96
114
|
bins.push(b.slice(i, i + len));
|
|
97
115
|
i += len - 1;
|
|
98
116
|
} break;
|
|
@@ -115,10 +133,107 @@ export default function decodeBson(b, codes = []) {
|
|
|
115
133
|
|
|
116
134
|
try {
|
|
117
135
|
let obj = JSON.parse(s);
|
|
118
|
-
if (bins.length)
|
|
136
|
+
if (bins.length) _makeBins(obj, bins);
|
|
119
137
|
return obj;
|
|
120
138
|
} catch (e) {
|
|
121
139
|
console.error(e, s);
|
|
122
140
|
throw new Error("JSON parse error");
|
|
123
141
|
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function _makeBins(obj, bins) {
|
|
145
|
+
if (typeof obj !== 'object') return;
|
|
146
|
+
for (let k in obj) {
|
|
147
|
+
if (typeof obj[k] === "object" && obj[k] !== null) {
|
|
148
|
+
_makeBins(obj[k], bins);
|
|
149
|
+
} else if (typeof obj[k] === "string" && obj[k].startsWith(BS_BIN_PREFIX)) {
|
|
150
|
+
obj[k] = bins[obj[k].slice(BS_BIN_PREFIX.length)];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {*} val
|
|
157
|
+
* @returns {Uint8Array}
|
|
158
|
+
*/
|
|
159
|
+
export function encodeBson(val) {
|
|
160
|
+
let arr = [];
|
|
161
|
+
_encode(val, arr);
|
|
162
|
+
return Uint8Array.from(arr);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function _encode(val, arr) {
|
|
166
|
+
if (Array.isArray(val)) {
|
|
167
|
+
arr.push(BS_CONTAINER | BS_CONT_ARR | BS_CONT_OPEN);
|
|
168
|
+
val.forEach(v => _encode(v, arr));
|
|
169
|
+
arr.push(BS_CONTAINER | BS_CONT_ARR | BS_CONT_CLOSE);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
switch (typeof val) {
|
|
174
|
+
case 'object':
|
|
175
|
+
if (val === null) {
|
|
176
|
+
arr.push(BS_NULL);
|
|
177
|
+
} else if (val instanceof Uint8Array) {
|
|
178
|
+
const len = Math.min(val.length, BS_MAX_LEN);
|
|
179
|
+
arr.push(BS_BINARY | BS_D16_MSB(len));
|
|
180
|
+
arr.push(BS_D16_LSB(len));
|
|
181
|
+
arr.push(...val.slice(0, len));
|
|
182
|
+
} else {
|
|
183
|
+
arr.push(BS_CONTAINER | BS_CONT_OBJ | BS_CONT_OPEN);
|
|
184
|
+
for (const [key, value] of Object.entries(val)) {
|
|
185
|
+
_encode(key, arr);
|
|
186
|
+
_encode(value, arr);
|
|
187
|
+
}
|
|
188
|
+
arr.push(BS_CONTAINER | BS_CONT_OBJ | BS_CONT_CLOSE);
|
|
189
|
+
}
|
|
190
|
+
break;
|
|
191
|
+
|
|
192
|
+
case 'bigint':
|
|
193
|
+
case 'number':
|
|
194
|
+
if (Number.isInteger(val)) {
|
|
195
|
+
val = BigInt(val);
|
|
196
|
+
const neg = val < 0;
|
|
197
|
+
if (neg) val = -val;
|
|
198
|
+
let bytes = [];
|
|
199
|
+
while (val) {
|
|
200
|
+
bytes.push(Number(val & 0xFFn));
|
|
201
|
+
val >>= 8n;
|
|
202
|
+
}
|
|
203
|
+
arr.push(BS_INTEGER | (neg ? BS_NEG_MASK : 0) | bytes.length);
|
|
204
|
+
arr.push(...bytes);
|
|
205
|
+
} else {
|
|
206
|
+
const buffer = new ArrayBuffer(BS_FLOAT_SIZE);
|
|
207
|
+
new DataView(buffer).setFloat32(0, val, true);
|
|
208
|
+
arr.push(BS_FLOAT | 4);
|
|
209
|
+
arr.push(...new Uint8Array(buffer));
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
|
|
213
|
+
case 'string':
|
|
214
|
+
if (val.startsWith(BS_CODE_PREFIX)) {
|
|
215
|
+
let code = Number(val.slice(BS_CODE_PREFIX.length));
|
|
216
|
+
arr.push(BS_CODE | BS_D16_MSB(code));
|
|
217
|
+
arr.push(BS_D16_LSB(code));
|
|
218
|
+
} else {
|
|
219
|
+
const bytes = new TextEncoder().encode(val);
|
|
220
|
+
const len = Math.min(bytes.length, BS_MAX_LEN);
|
|
221
|
+
arr.push(BS_STRING | BS_D16_MSB(len));
|
|
222
|
+
arr.push(BS_D16_LSB(len));
|
|
223
|
+
arr.push(...bytes.slice(0, len));
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
|
|
227
|
+
case 'boolean':
|
|
228
|
+
arr.push(BS_BOOLEAN | (val ? 1 : 0));
|
|
229
|
+
break;
|
|
230
|
+
|
|
231
|
+
default:
|
|
232
|
+
arr.push(BS_NULL);
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function getCode(name, codes) {
|
|
238
|
+
return BS_CODE_PREFIX + codes.indexOf(name);
|
|
124
239
|
}
|
package/bson.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e={d:(r
|
|
1
|
+
var e={d:(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{$R:()=>U,QC:()=>C,lo:()=>F});const r=0,n=32,s=64,o=96,a=128,c=160,i=192,l=224,u=16,h=8,f=4,p=2,b=8191,g=e=>224&e,y=e=>31&e,d=e=>1&e,w=16,O=e=>e&w,N=e=>15&e,k=4,A=e=>15&e,B=e=>e>>8&31,m=e=>255&e,_=(e,t)=>(e<<8|t)>>>0,j="__BSON_BIN_",x="__BSON_CODE_";function F(e,t=[]){if(!(e&&e instanceof Uint8Array))return null;if(!e.length)return{};let f=[],p=[],b=!0,w="";try{for(let B=0;B<e.length;B++){const m=g(e[B]),x=y(e[B]);switch(m){case i:if(x&h){let e=x&u?"{":"[";w+=e,p.push(e)}else","==w[w.length-1]&&(w=w.slice(0,-1)),w+=(x&u?"}":"]")+",",p.pop();b=!0;continue;case a:w+='"'+t[_(x,e[++B])]+'"';break;case r:{let t=_(x,e[++B]);w+=JSON.stringify((new TextDecoder).decode(e.slice(B+1,B+1+t))),B+=t}break;case s:{O(x)&&(w+="-");let t=N(x),r=new Uint8Array(8);r.set(e.slice(B+1,B+1+t)),w+=new BigUint64Array(r.buffer)[0],B+=t}break;case n:w+=d(x)?"true":"false";break;case l:w+="null";break;case o:{let t=new DataView(e.buffer,e.byteOffset+B+1,k).getFloat32(0,!0);w+=isNaN(t)||!isFinite(t)?"null":t.toFixed(A(x)),B+=k}break;case c:{let t=_(x,e[++B]);B++,w+='"'+j+f.length+'"',f.push(e.slice(B,B+t)),B+=t-1}}"{"===p[p.length-1]?(w+=b?":":",",b=!b):w+=","}}catch(e){throw console.error(e,w),new Error("BSON decode error")}","==w[w.length-1]&&(w=w.slice(0,-1));try{let e=JSON.parse(w);return f.length&&S(e,f),e}catch(e){throw console.error(e,w),new Error("JSON parse error")}}function S(e,t){if("object"==typeof e)for(let r in e)"object"==typeof e[r]&&null!==e[r]?S(e[r],t):"string"==typeof e[r]&&e[r].startsWith(j)&&(e[r]=t[e[r].slice(j.length)])}function U(e){let t=[];return E(e,t),Uint8Array.from(t)}function E(e,t){if(Array.isArray(e))return t.push(i|f|h),e.forEach(e=>E(e,t)),void t.push(i|f|p);switch(typeof e){case"object":if(null===e)t.push(l);else if(e instanceof Uint8Array){const r=Math.min(e.length,b);t.push(c|B(r)),t.push(m(r)),t.push(...e.slice(0,r))}else{t.push(i|u|h);for(const[r,n]of Object.entries(e))E(r,t),E(n,t);t.push(i|u|p)}break;case"bigint":case"number":if(Number.isInteger(e)){const r=(e=BigInt(e))<0;r&&(e=-e);let n=[];for(;e;)n.push(Number(0xFFn&e)),e>>=8n;t.push(s|(r?w:0)|n.length),t.push(...n)}else{const r=new ArrayBuffer(k);new DataView(r).setFloat32(0,e,!0),t.push(4|o),t.push(...new Uint8Array(r))}break;case"string":if(e.startsWith(x)){let r=Number(e.slice(x.length));t.push(a|B(r)),t.push(m(r))}else{const n=(new TextEncoder).encode(e),s=Math.min(n.length,b);t.push(r|B(s)),t.push(m(s)),t.push(...n.slice(0,s))}break;case"boolean":t.push(n|(e?1:0));break;default:t.push(l)}}function C(e,t){return x+t.indexOf(e)}const D=t.lo,v=t.$R,I=t.QC;export{D as decodeBson,v as encodeBson,I as getCode};
|
package/package.json
CHANGED
package/test.html
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
<p id="out" style="white-space: break-spaces;"></p>
|
|
6
6
|
|
|
7
7
|
<script type="module">
|
|
8
|
-
import decodeBson from 'https://gyverlibs.github.io/bson.js/dist/bson.js';
|
|
8
|
+
import { decodeBson, encodeBson, getCode } from 'https://gyverlibs.github.io/bson.js/dist/bson.js';
|
|
9
|
+
// import { decodeBson, encodeBson, getCode } from '/bson.js';
|
|
9
10
|
|
|
10
11
|
const url = 'http://192.168.1.54';
|
|
11
12
|
|
|
@@ -15,6 +16,34 @@
|
|
|
15
16
|
'constants',
|
|
16
17
|
];
|
|
17
18
|
|
|
19
|
+
// =========== getCode ===========
|
|
20
|
+
console.log(getCode('constants', codes));
|
|
21
|
+
|
|
22
|
+
// =========== encode ===========
|
|
23
|
+
let test = {
|
|
24
|
+
int: 123,
|
|
25
|
+
float: 3.14,
|
|
26
|
+
arr: [
|
|
27
|
+
"str",
|
|
28
|
+
true,
|
|
29
|
+
1234,
|
|
30
|
+
new Uint8Array([1, 2, 3]),
|
|
31
|
+
],
|
|
32
|
+
obj: {
|
|
33
|
+
str2: "str2",
|
|
34
|
+
true: true,
|
|
35
|
+
},
|
|
36
|
+
str3: "str3",
|
|
37
|
+
nul: null,
|
|
38
|
+
[getCode('constants', codes)]: getCode('string', codes),
|
|
39
|
+
bins: new Uint8Array([1, 2, 3]),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
let enc = encodeBson(test);
|
|
43
|
+
let json = decodeBson(enc, codes);
|
|
44
|
+
console.log(json);
|
|
45
|
+
|
|
46
|
+
// =========== request ===========
|
|
18
47
|
req.onclick = async () => {
|
|
19
48
|
let res = await fetch(url + '/bson');
|
|
20
49
|
try {
|