@alexgyver/bson 2.0.2 → 2.1.1

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # bson.js
2
- Распаковщик бинарного JSON для библиотеки [BSON](https://github.com/GyverLibs/BSON).
2
+ Распаковщик и запаковщик бинарного JSON для библиотеки [BSON](https://github.com/GyverLibs/BSON).
3
3
 
4
4
  > npm i @alexgyver/bson
5
5
 
@@ -10,10 +10,26 @@ const codes = [
10
10
  'constants',
11
11
  ];
12
12
 
13
- let json;
14
- const res = await fetch(...);
13
+ let test = {
14
+ int: 123,
15
+ float: 3.14,
16
+ arr: [
17
+ "str",
18
+ true,
19
+ 1234,
20
+ new Uint8Array([1, 2, 3]),
21
+ ],
22
+ obj: {
23
+ str2: "str2",
24
+ true: true,
25
+ },
26
+ str3: "str3",
27
+ nul: null,
28
+ [getCode('constants', codes)]: getCode('string', codes),
29
+ bins: new Uint8Array([1, 2, 3]),
30
+ };
15
31
 
16
- try {
17
- json = decodeBson(new Uint8Array(await res.arrayBuffer()), codes);
18
- } catch (e) { }
32
+ let enc = encodeBson(test);
33
+ let json = decodeBson(enc, codes);
34
+ console.log(json);
19
35
  ```
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 default function decodeBson(b, codes = []) {
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] & 0b11100000;
45
- const data = b[i] & 0b00011111;
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[unpack5(data, b[++i])] + '"';
77
+ s += '"' + codes[BS_D16_MERGE(data, b[++i])] + '"';
65
78
  break;
66
79
 
67
80
  case BS_STRING: {
68
- let len = unpack5(data, b[++i]);
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 & BS_NEGATIVE) s += '-';
75
- let len = data & 0b1111;
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 & 0b1) ? 'true' : 'false';
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 Float32Array(b.slice(i + 1, i + 1 + 4).buffer)[0];
88
- s += (isNaN(f) || !isFinite(f)) ? 'null' : f.toFixed(data);
89
- i += 4;
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 = unpack5(data, b[++i]);
111
+ let len = BS_D16_MERGE(data, b[++i]);
94
112
  i++;
95
- s += '"' + BS_BIN_PREFIX + '#' + bins.length + '"';
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,112 @@ export default function decodeBson(b, codes = []) {
115
133
 
116
134
  try {
117
135
  let obj = JSON.parse(s);
118
- if (bins.length) makeBins(obj, bins);
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, codes = []) {
160
+ let arr = [];
161
+ _encode(val, arr, codes);
162
+ return Uint8Array.from(arr);
163
+ }
164
+
165
+ function _encode(val, arr, codes) {
166
+ if (Array.isArray(val)) {
167
+ arr.push(BS_CONTAINER | BS_CONT_ARR | BS_CONT_OPEN);
168
+ val.forEach(v => _encode(v, arr, codes));
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, codes);
186
+ _encode(value, arr, codes);
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
+ val = val.slice(BS_CODE_PREFIX.length);
216
+ let code = codes.indexOf(val);
217
+ if (code >= 0) {
218
+ arr.push(BS_CODE | BS_D16_MSB(code));
219
+ arr.push(BS_D16_LSB(code));
220
+ } else {
221
+ _encode(val, arr, codes);
222
+ }
223
+ } else {
224
+ const bytes = new TextEncoder().encode(val);
225
+ const len = Math.min(bytes.length, BS_MAX_LEN);
226
+ arr.push(BS_STRING | BS_D16_MSB(len));
227
+ arr.push(BS_D16_LSB(len));
228
+ arr.push(...bytes.slice(0, len));
229
+ }
230
+ break;
231
+
232
+ case 'boolean':
233
+ arr.push(BS_BOOLEAN | (val ? 1 : 0));
234
+ break;
235
+
236
+ default:
237
+ arr.push(BS_NULL);
238
+ break;
239
+ }
240
+ }
241
+
242
+ export function getCode(name) {
243
+ return BS_CODE_PREFIX + name;
124
244
  }
package/bson.min.js CHANGED
@@ -1 +1 @@
1
- var e={d:(r,t)=>{for(var n in t)e.o(t,n)&&!e.o(r,n)&&Object.defineProperty(r,n,{enumerable:!0,get:t[n]})},o:(e,r)=>Object.prototype.hasOwnProperty.call(e,r)},r={};function t(e,r=[]){if(!(e&&e instanceof Uint8Array))return null;if(!e.length)return{};const t="__BSON_BINARY";function n(e,r){return(e<<8|r)>>>0}let o=[],l=[],c=!0,s="";try{for(let i=0;i<e.length;i++){const a=224&e[i],f=31&e[i];switch(a){case 192:if(8&f){let e=16&f?"{":"[";s+=e,l.push(e)}else","==s[s.length-1]&&(s=s.slice(0,-1)),s+=(16&f?"}":"]")+",",l.pop();c=!0;continue;case 128:s+='"'+r[n(f,e[++i])]+'"';break;case 0:{let r=n(f,e[++i]);s+=JSON.stringify((new TextDecoder).decode(e.slice(i+1,i+1+r))),i+=r}break;case 64:{16&f&&(s+="-");let r=15&f,t=new Uint8Array(8);t.set(e.slice(i+1,i+1+r)),s+=new BigUint64Array(t.buffer)[0],i+=r}break;case 32:s+=1&f?"true":"false";break;case 96:{let r=new Float32Array(e.slice(i+1,i+1+4).buffer)[0];s+=isNaN(r)||!isFinite(r)?"null":r.toFixed(f),i+=4}break;case 160:{let r=n(f,e[++i]);i++,s+='"'+t+"#"+o.length+'"',o.push(e.slice(i,i+r)),i+=r-1}}"{"===l[l.length-1]?(s+=c?":":",",c=!c):s+=","}}catch(e){throw console.error(e,s),new Error("BSON decode error")}","==s[s.length-1]&&(s=s.slice(0,-1));try{let e=JSON.parse(s);return o.length&&function e(r,n){if("object"==typeof r)for(let o in r)"object"==typeof r[o]&&null!==r[o]?e(r[o],n):"string"==typeof r[o]&&r[o].startsWith(t)&&(r[o]=n[r[o].split("#")[1]])}(e,o),e}catch(e){throw console.error(e,s),new Error("JSON parse error")}}e.d(r,{A:()=>t});const n=r.A;export{n as default};
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,_=e=>255&e,m=(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 _=g(e[B]),x=y(e[B]);switch(_){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[m(x,e[++B])]+'"';break;case r:{let t=m(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=m(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,t=[]){let r=[];return E(e,r,t),Uint8Array.from(r)}function E(e,t,g){if(Array.isArray(e))return t.push(i|f|h),e.forEach(e=>E(e,t,g)),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(_(r)),t.push(...e.slice(0,r))}else{t.push(i|u|h);for(const[r,n]of Object.entries(e))E(r,t,g),E(n,t,g);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)){e=e.slice(x.length);let r=g.indexOf(e);r>=0?(t.push(a|B(r)),t.push(_(r))):E(e,t,g)}else{const n=(new TextEncoder).encode(e),s=Math.min(n.length,b);t.push(r|B(s)),t.push(_(s)),t.push(...n.slice(0,s))}break;case"boolean":t.push(n|(e?1:0));break;default:t.push(l)}}function C(e){return x+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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexgyver/bson",
3
- "version": "2.0.2",
3
+ "version": "2.1.1",
4
4
  "description": "Decode BSON from BSON Arduino library",
5
5
  "main": "./bson.js",
6
6
  "module": "./bson.js",
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,32 @@
15
16
  'constants',
16
17
  ];
17
18
 
19
+ // =========== encode ===========
20
+ let test = {
21
+ int: 123,
22
+ float: 3.14,
23
+ arr: [
24
+ "str",
25
+ true,
26
+ 1234,
27
+ new Uint8Array([1, 2, 3]),
28
+ ],
29
+ obj: {
30
+ str2: "str2",
31
+ true: true,
32
+ },
33
+ str3: "str3",
34
+ nul: null,
35
+ [getCode('constants1')]: getCode('string1'),
36
+ [getCode('constants')]: getCode('string'),
37
+ bins: new Uint8Array([1, 2, 3]),
38
+ };
39
+
40
+ let enc = encodeBson(test, codes);
41
+ let json = decodeBson(enc, codes);
42
+ console.log(json);
43
+
44
+ // =========== request ===========
18
45
  req.onclick = async () => {
19
46
  let res = await fetch(url + '/bson');
20
47
  try {