@andrew_l/tl-pack 0.2.15 → 0.2.16

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.
@@ -1,5 +1,5 @@
1
1
  import pako from 'pako';
2
- import { isPlainObject } from '@andrew_l/toolkit';
2
+ import { noop as noop$1, crc32, assert, isPlainObject } from '@andrew_l/toolkit';
3
3
 
4
4
  var CORE_TYPES = /* @__PURE__ */ ((CORE_TYPES2) => {
5
5
  CORE_TYPES2[CORE_TYPES2["None"] = 0] = "None";
@@ -25,6 +25,7 @@ var CORE_TYPES = /* @__PURE__ */ ((CORE_TYPES2) => {
25
25
  CORE_TYPES2[CORE_TYPES2["Repeat"] = 20] = "Repeat";
26
26
  CORE_TYPES2[CORE_TYPES2["Checksum"] = 21] = "Checksum";
27
27
  CORE_TYPES2[CORE_TYPES2["GZIP"] = 25] = "GZIP";
28
+ CORE_TYPES2[CORE_TYPES2["Structure"] = 26] = "Structure";
28
29
  return CORE_TYPES2;
29
30
  })(CORE_TYPES || {});
30
31
  const MAX_BUFFER_SIZE = 2144337920;
@@ -79,1074 +80,1501 @@ class Dictionary {
79
80
  }
80
81
  }
81
82
 
82
- const encoder = new TextEncoder();
83
- const decoder = new TextDecoder();
84
- const fromCharCode = String.fromCharCode;
85
- const int32 = new Int32Array(2);
86
- const float32 = new Float32Array(int32.buffer);
87
- const float64 = new Float64Array(int32.buffer);
88
- function byteArrayAllocate(length) {
89
- return new Uint8Array(length);
90
- }
91
- function coreType(value) {
92
- switch (typeof value) {
93
- case "string": {
94
- return CORE_TYPES.String;
95
- }
96
- case "boolean": {
97
- return value ? CORE_TYPES.BoolTrue : CORE_TYPES.BoolFalse;
98
- }
99
- case "number": {
100
- if (Math.trunc(value) === value) {
101
- if (value >= 0 && value <= 255) {
102
- return CORE_TYPES.UInt8;
103
- } else if (value >= 0 && value <= 65535) {
104
- return CORE_TYPES.UInt16;
105
- } else if (value >= 0 && value <= 4294967295) {
106
- return CORE_TYPES.UInt32;
107
- } else if (value >= -128 && value <= 127) {
108
- return CORE_TYPES.Int8;
109
- } else if (value >= -32768 && value <= 32767) {
110
- return CORE_TYPES.Int16;
111
- } else if (value >= -2147483648 && value <= 2147483647) {
112
- return CORE_TYPES.Int32;
113
- }
83
+ const noop = Symbol();
84
+ const NO_CONSTRUCTOR = /* @__PURE__ */ new Set([
85
+ CORE_TYPES.BoolFalse,
86
+ CORE_TYPES.BoolTrue,
87
+ CORE_TYPES.Null
88
+ ]);
89
+ const SUPPORT_COMPRESSION = /* @__PURE__ */ new Set([CORE_TYPES.String]);
90
+ const NOOP_DICTIONARY$1 = new Dictionary();
91
+ class BinaryWriter {
92
+ withGzip;
93
+ target;
94
+ dictionary;
95
+ dictionaryExtended;
96
+ extensions;
97
+ structures;
98
+ _last;
99
+ offsetChecksum;
100
+ _repeat;
101
+ offset;
102
+ constructor({
103
+ gzip = false,
104
+ dictionary = NOOP_DICTIONARY$1,
105
+ extensions,
106
+ structures
107
+ } = {}) {
108
+ this.offset = 0;
109
+ this.offsetChecksum = 0;
110
+ this.extensions = /* @__PURE__ */ new Map();
111
+ this.structures = /* @__PURE__ */ new Map();
112
+ this.withGzip = gzip;
113
+ this.target = byteArrayAllocate(8192);
114
+ this._last = noop;
115
+ if (extensions) {
116
+ for (const ext of extensions) {
117
+ this.extensions.set(ext.token, ext);
114
118
  }
115
- return CORE_TYPES.Double;
116
119
  }
117
- case "object": {
118
- if (value === null) return CORE_TYPES.Null;
119
- if (value instanceof Date) {
120
- return CORE_TYPES.Date;
121
- }
122
- if (Array.isArray(value)) {
123
- return CORE_TYPES.Vector;
124
- }
125
- if (isPlainObject(value)) {
126
- return CORE_TYPES.Map;
120
+ if (structures) {
121
+ for (const struct of structures) {
122
+ this.structures.set(struct.extension.token, struct);
127
123
  }
128
124
  }
125
+ if (Array.isArray(dictionary)) {
126
+ this.dictionary = new Dictionary(dictionary);
127
+ } else {
128
+ this.dictionary = dictionary;
129
+ }
130
+ this.dictionaryExtended = new Dictionary(void 0, this.dictionary.size);
129
131
  }
130
- return CORE_TYPES.None;
131
- }
132
- function utf8Read(target, length, offset) {
133
- let result;
134
- if (length < 16) {
135
- if (result = utf8ReadShort(target, length, offset)) return result;
132
+ /**
133
+ * Reset internal state
134
+ */
135
+ reset() {
136
+ this.offset = 0;
137
+ this.offsetChecksum = 0;
138
+ this._last = noop;
139
+ this._repeat = void 0;
140
+ this.dictionaryExtended = new Dictionary(void 0, this.dictionary.size);
141
+ return this;
136
142
  }
137
- if (length > 64 && decoder)
138
- return decoder.decode(target.subarray(offset, offset += length));
139
- const end = offset + length;
140
- const units = [];
141
- result = "";
142
- while (offset < end) {
143
- const byte1 = target[offset++];
144
- if ((byte1 & 128) === 0) {
145
- units.push(byte1);
146
- } else if ((byte1 & 224) === 192) {
147
- const byte2 = target[offset++] & 63;
148
- units.push((byte1 & 31) << 6 | byte2);
149
- } else if ((byte1 & 240) === 224) {
150
- const byte2 = target[offset++] & 63;
151
- const byte3 = target[offset++] & 63;
152
- units.push((byte1 & 31) << 12 | byte2 << 6 | byte3);
153
- } else if ((byte1 & 248) === 240) {
154
- const byte2 = target[offset++] & 63;
155
- const byte3 = target[offset++] & 63;
156
- const byte4 = target[offset++] & 63;
157
- let unit = (byte1 & 7) << 18 | byte2 << 12 | byte3 << 6 | byte4;
158
- if (unit > 65535) {
159
- unit -= 65536;
160
- units.push(unit >>> 10 & 1023 | 55296);
161
- unit = 56320 | unit & 1023;
162
- }
163
- units.push(unit);
143
+ allocate(size) {
144
+ const position = this.offset + size;
145
+ if (this.safeEnd < position) {
146
+ this.makeRoom(position);
147
+ }
148
+ return this;
149
+ }
150
+ makeRoom(end) {
151
+ let start = 0;
152
+ let newSize = 0;
153
+ let target = this.target;
154
+ if (end > 16777216) {
155
+ if (end - start > MAX_BUFFER_SIZE)
156
+ throw new Error(
157
+ "Packed buffer would be larger than maximum buffer size"
158
+ );
159
+ newSize = Math.min(
160
+ MAX_BUFFER_SIZE,
161
+ Math.round(
162
+ Math.max((end - start) * (end > 67108864 ? 1.25 : 2), 4194304) / 4096
163
+ ) * 4096
164
+ );
164
165
  } else {
165
- units.push(byte1);
166
+ newSize = (Math.max(end - start << 2, target.length - 1) >> 12) + 1 << 12;
166
167
  }
167
- if (units.length >= 4096) {
168
- result += fromCharCode.apply(String, units);
169
- units.length = 0;
168
+ const newBuffer = byteArrayAllocate(newSize);
169
+ end = Math.min(end, target.length);
170
+ newBuffer.set(target.slice(start, end));
171
+ this.target = newBuffer;
172
+ }
173
+ get safeEnd() {
174
+ return this.target.length - 10;
175
+ }
176
+ getBuffer() {
177
+ return this.target.subarray(0, this.offset);
178
+ }
179
+ writeByte(value) {
180
+ this.allocate(1);
181
+ this.target[this.offset++] = value;
182
+ return this;
183
+ }
184
+ writeBool(value) {
185
+ if (value) {
186
+ this.writeByte(CORE_TYPES.BoolTrue);
187
+ } else {
188
+ this.writeByte(CORE_TYPES.BoolFalse);
170
189
  }
190
+ return this;
171
191
  }
172
- if (units.length > 0) {
173
- result += fromCharCode.apply(String, units);
192
+ writeNull() {
193
+ this.writeByte(CORE_TYPES.Null);
194
+ return this;
174
195
  }
175
- return result;
176
- }
177
- function utf8ReadShort(target, length, offset) {
178
- if (length < 4) {
179
- if (length < 2) {
180
- if (length === 0) return "";
181
- else {
182
- let a = target[offset++];
183
- if ((a & 128) > 1) {
184
- offset -= 1;
185
- return;
186
- }
187
- return fromCharCode(a);
188
- }
196
+ writeInt32(value, signed = true) {
197
+ this.allocate(4);
198
+ if (signed) {
199
+ this.target[this.offset++] = value;
200
+ this.target[this.offset++] = value >> 8;
201
+ this.target[this.offset++] = value >> 16;
202
+ this.target[this.offset++] = value >> 24;
189
203
  } else {
190
- let a = target[offset++];
191
- let b = target[offset++];
192
- if ((a & 128) > 0 || (b & 128) > 0) {
193
- offset -= 2;
194
- return;
195
- }
196
- if (length < 3) return fromCharCode(a, b);
197
- let c = target[offset++];
198
- if ((c & 128) > 0) {
199
- offset -= 3;
200
- return;
201
- }
202
- return fromCharCode(a, b, c);
204
+ this.target[this.offset++] = value;
205
+ this.target[this.offset++] = value >> 8;
206
+ this.target[this.offset++] = value >> 16;
207
+ this.target[this.offset++] = value >> 24;
203
208
  }
204
- } else {
205
- let a = target[offset++];
206
- let b = target[offset++];
207
- let c = target[offset++];
208
- let d = target[offset++];
209
- if ((a & 128) > 0 || (b & 128) > 0 || (c & 128) > 0 || (d & 128) > 0) {
210
- offset -= 4;
211
- return;
209
+ return this;
210
+ }
211
+ writeInt16(value, signed = true) {
212
+ this.allocate(2);
213
+ if (signed) {
214
+ this.target[this.offset++] = value;
215
+ this.target[this.offset++] = value >> 8;
216
+ } else {
217
+ this.target[this.offset++] = value;
218
+ this.target[this.offset++] = value >> 8;
212
219
  }
213
- if (length < 6) {
214
- if (length === 4) return fromCharCode(a, b, c, d);
215
- else {
216
- let e = target[offset++];
217
- if ((e & 128) > 0) {
218
- offset -= 5;
219
- return;
220
- }
221
- return fromCharCode(a, b, c, d, e);
222
- }
223
- } else if (length < 8) {
224
- let e = target[offset++];
225
- let f = target[offset++];
226
- if ((e & 128) > 0 || (f & 128) > 0) {
227
- offset -= 6;
228
- return;
229
- }
230
- if (length < 7) return fromCharCode(a, b, c, d, e, f);
231
- let g = target[offset++];
232
- if ((g & 128) > 0) {
233
- offset -= 7;
234
- return;
235
- }
236
- return fromCharCode(a, b, c, d, e, f, g);
220
+ return this;
221
+ }
222
+ writeInt8(value, signed = true) {
223
+ this.allocate(1);
224
+ this.target[this.offset++] = value;
225
+ return this;
226
+ }
227
+ writeFloat(value) {
228
+ this.allocate(4);
229
+ float32[0] = value;
230
+ this.writeInt32(int32[0]);
231
+ return this;
232
+ }
233
+ writeDouble(value) {
234
+ this.allocate(8);
235
+ float64[0] = value;
236
+ this.writeInt32(int32[0], false);
237
+ this.writeInt32(int32[1], false);
238
+ return this;
239
+ }
240
+ writeDate(value) {
241
+ let timestamp = 0;
242
+ if (value instanceof Date) {
243
+ timestamp = value.getTime();
244
+ } else if (typeof value === "number") {
245
+ timestamp = value;
246
+ }
247
+ this.writeDouble(timestamp);
248
+ return this;
249
+ }
250
+ writeString(value) {
251
+ const strLength = value.length;
252
+ let start = this.offset;
253
+ let require = strLength << 2;
254
+ if (require < 254) {
255
+ require += 1;
256
+ this.offset += 1;
237
257
  } else {
238
- let e = target[offset++];
239
- let f = target[offset++];
240
- let g = target[offset++];
241
- let h = target[offset++];
242
- if ((e & 128) > 0 || (f & 128) > 0 || (g & 128) > 0 || (h & 128) > 0) {
243
- offset -= 8;
244
- return;
245
- }
246
- if (length < 10) {
247
- if (length === 8) return fromCharCode(a, b, c, d, e, f, g, h);
248
- else {
249
- let i = target[offset++];
250
- if ((i & 128) > 0) {
251
- offset -= 9;
252
- return;
253
- }
254
- return fromCharCode(a, b, c, d, e, f, g, h, i);
255
- }
256
- } else if (length < 12) {
257
- let i = target[offset++];
258
- let j = target[offset++];
259
- if ((i & 128) > 0 || (j & 128) > 0) {
260
- offset -= 10;
261
- return;
262
- }
263
- if (length < 11) return fromCharCode(a, b, c, d, e, f, g, h, i, j);
264
- let k = target[offset++];
265
- if ((k & 128) > 0) {
266
- offset -= 11;
267
- return;
268
- }
269
- return fromCharCode(a, b, c, d, e, f, g, h, i, j, k);
258
+ require += 4;
259
+ this.offset += 4;
260
+ }
261
+ this.allocate(require);
262
+ const bytes = utf8Write(this.target, value, this.offset);
263
+ if (require < 254) {
264
+ this.target[start++] = bytes;
265
+ } else {
266
+ this.target[start++] = 254;
267
+ this.target[start++] = bytes % 256;
268
+ this.target[start++] = (bytes >> 8) % 256;
269
+ this.target[start++] = (bytes >> 16) % 256;
270
+ }
271
+ this.offset += bytes;
272
+ return this;
273
+ }
274
+ writeChecksum(withConstructor = true) {
275
+ const bytes = this.target.slice(this.offsetChecksum, this.offset);
276
+ let sum = 0;
277
+ for (const val of bytes) {
278
+ sum += val;
279
+ }
280
+ if (withConstructor) {
281
+ this.writeByte(CORE_TYPES.Checksum);
282
+ }
283
+ this.writeInt32(sum);
284
+ this.offsetChecksum = this.offset;
285
+ return this;
286
+ }
287
+ writeBytes(value) {
288
+ const length = value.length;
289
+ this.writeLength(length);
290
+ this.allocate(length);
291
+ this.target.set(value, this.offset);
292
+ this.offset += length;
293
+ return this;
294
+ }
295
+ writeLength(value) {
296
+ if (value < 254) {
297
+ this.allocate(1);
298
+ this.target[this.offset++] = value;
299
+ } else {
300
+ this.allocate(4);
301
+ this.target[this.offset++] = 254;
302
+ this.target[this.offset++] = value % 256;
303
+ this.target[this.offset++] = (value >> 8) % 256;
304
+ this.target[this.offset++] = (value >> 16) % 256;
305
+ }
306
+ return this;
307
+ }
308
+ writeVector(value) {
309
+ const length = value.length;
310
+ this.writeLength(length);
311
+ for (let i = 0; i < length; i++) {
312
+ if (value[i] === void 0) {
313
+ this.writeNull();
270
314
  } else {
271
- let i = target[offset++];
272
- let j = target[offset++];
273
- let k = target[offset++];
274
- let l = target[offset++];
275
- if ((i & 128) > 0 || (j & 128) > 0 || (k & 128) > 0 || (l & 128) > 0) {
276
- offset -= 12;
277
- return;
278
- }
279
- if (length < 14) {
280
- if (length === 12)
281
- return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l);
282
- else {
283
- let m = target[offset++];
284
- if ((m & 128) > 0) {
285
- offset -= 13;
286
- return;
287
- }
288
- return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m);
289
- }
290
- } else {
291
- let m = target[offset++];
292
- let n = target[offset++];
293
- if ((m & 128) > 0 || (n & 128) > 0) {
294
- offset -= 14;
295
- return;
296
- }
297
- if (length < 15)
298
- return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n);
299
- let o = target[offset++];
300
- if ((o & 128) > 0) {
301
- offset -= 15;
302
- return;
303
- }
304
- return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
305
- }
315
+ this.writeObject(value[i]);
306
316
  }
307
317
  }
318
+ return this;
308
319
  }
309
- }
310
- const utf8Write = function(target, value, offset) {
311
- return value.length < 64 ? utf8WriteShort(target, value, offset) : encoder.encodeInto(value, target.subarray(offset)).written;
312
- };
313
- const utf8WriteShort = (target, value, offset) => {
314
- let i, c1, c2, strPosition = offset;
315
- const strLength = value.length;
316
- for (i = 0; i < strLength; i++) {
317
- c1 = value.charCodeAt(i);
318
- if (c1 < 128) {
319
- target[strPosition++] = c1;
320
- } else if (c1 < 2048) {
321
- target[strPosition++] = c1 >> 6 | 192;
322
- target[strPosition++] = c1 & 63 | 128;
323
- } else if ((c1 & 64512) === 55296 && ((c2 = value.charCodeAt(i + 1)) & 64512) === 56320) {
324
- c1 = 65536 + ((c1 & 1023) << 10) + (c2 & 1023);
325
- i++;
326
- target[strPosition++] = c1 >> 18 | 240;
327
- target[strPosition++] = c1 >> 12 & 63 | 128;
328
- target[strPosition++] = c1 >> 6 & 63 | 128;
329
- target[strPosition++] = c1 & 63 | 128;
320
+ writeMap(object) {
321
+ for (const key in object) {
322
+ if (object[key] === void 0) continue;
323
+ this._last = noop;
324
+ this.wireDictionary(key);
325
+ this.writeObject(object[key]);
326
+ }
327
+ this.writeByte(CORE_TYPES.None);
328
+ return this;
329
+ }
330
+ wireDictionary(value) {
331
+ let idx = null;
332
+ idx = this.dictionary.getIndex(value);
333
+ if (idx === null) {
334
+ idx = this.dictionaryExtended.getIndex(value);
335
+ }
336
+ if (idx === null) {
337
+ this.dictionaryExtended.maybeInsert(value);
338
+ this.writeCore(CORE_TYPES.DictValue, value);
330
339
  } else {
331
- target[strPosition++] = c1 >> 12 | 224;
332
- target[strPosition++] = c1 >> 6 & 63 | 128;
333
- target[strPosition++] = c1 & 63 | 128;
340
+ this.writeCore(CORE_TYPES.DictIndex, idx);
334
341
  }
342
+ return this;
335
343
  }
336
- return strPosition - offset;
337
- };
338
-
339
- class BinaryReader {
340
- target;
341
- _last;
342
- _lastObject;
343
- dictionary;
344
- dictionaryExtended;
345
- extensions;
346
- _repeat;
347
- _checksumOffset;
348
- offset;
349
- length;
350
- /**
351
- * Small utility class to read binary data.
352
- */
353
- constructor(data, options) {
354
- this.target = data;
344
+ writeStructure(value) {
345
+ const ctor = value.constructor;
346
+ this.writeInt32(ctor.extension.token, false);
347
+ ctor.extension.encode.call(this, value.value);
348
+ return this;
349
+ }
350
+ writeGzip(value) {
351
+ const compressed = pako.deflateRaw(value, { level: 9 });
352
+ this.writeBytes(compressed);
353
+ return this;
354
+ }
355
+ encode(value) {
355
356
  this.offset = 0;
356
- this._checksumOffset = 0;
357
- this.length = data.length;
358
- this.extensions = /* @__PURE__ */ new Map();
359
- if (options && options.extensions) {
360
- options.extensions.forEach((ext) => {
361
- this.extensions.set(ext.token, ext);
362
- });
357
+ this.offsetChecksum = 0;
358
+ this._last = noop;
359
+ this._repeat = void 0;
360
+ this.target = byteArrayAllocate(256);
361
+ this.writeObject(value);
362
+ return this.getBuffer();
363
+ }
364
+ startDynamicVector() {
365
+ this.writeByte(CORE_TYPES.VectorDynamic);
366
+ return this;
367
+ }
368
+ endDynamicVector() {
369
+ this.writeByte(CORE_TYPES.None);
370
+ return this;
371
+ }
372
+ _writeCustom(value) {
373
+ const start = this.offset;
374
+ this.allocate(1);
375
+ this.offset++;
376
+ let edgeExt;
377
+ for (const ext of this.extensions.values()) {
378
+ if (ext.token === -1) {
379
+ edgeExt = ext;
380
+ continue;
381
+ }
382
+ ext.encode.call(this, value);
383
+ const processed = start + 1 < this.offset;
384
+ if (processed) {
385
+ const end = this.offset;
386
+ this.offset = start;
387
+ this.writeByte(ext.token);
388
+ this.offset = end;
389
+ return true;
390
+ }
391
+ }
392
+ this.offset = start;
393
+ if (edgeExt) {
394
+ edgeExt.encode.call(this, value);
395
+ return start < this.offset;
396
+ }
397
+ return false;
398
+ }
399
+ writeObject(value) {
400
+ if (value === void 0) return this;
401
+ const constructorId = coreType(value);
402
+ if (constructorId === CORE_TYPES.None) {
403
+ if (this._writeCustom(value)) {
404
+ return this;
405
+ }
406
+ throw new TypeError(`Invalid core type of ${value}`);
363
407
  }
364
- if (!options) {
365
- this.dictionary = new Dictionary();
366
- } else if (options.dictionary instanceof Dictionary) {
367
- this.dictionary = options.dictionary;
368
- } else if (Array.isArray(options.dictionary)) {
369
- this.dictionary = new Dictionary(options.dictionary);
408
+ if (this._last === value) {
409
+ this.writeRepeat();
370
410
  } else {
371
- this.dictionary = new Dictionary();
411
+ this._last = value;
412
+ this._repeat = void 0;
413
+ this.writeCore(constructorId, value);
372
414
  }
373
- this.dictionaryExtended = new Dictionary(void 0, this.dictionary.size);
415
+ return this;
374
416
  }
375
- readByte() {
376
- this.assertRead(1);
377
- this._last = this.target[this.offset++];
378
- return this._last;
417
+ writeObjectGzip(value) {
418
+ const writer = new BinaryWriter();
419
+ writer.extensions = this.extensions;
420
+ writer.dictionary = this.dictionary;
421
+ writer.structures = this.structures;
422
+ writer.dictionaryExtended = this.dictionaryExtended;
423
+ writer.writeObject(value);
424
+ this.writeCore(CORE_TYPES.GZIP, writer.getBuffer());
425
+ return this;
379
426
  }
380
- readInt32(signed = true) {
381
- this.assertRead(4);
382
- this._last = this.target[this.offset++] | this.target[this.offset++] << 8 | this.target[this.offset++] << 16 | this.target[this.offset++] << 24;
383
- if (!signed) {
384
- this._last = this._last >>> 0;
427
+ writeCore(constructorId, value) {
428
+ if (this.withGzip && SUPPORT_COMPRESSION.has(constructorId)) {
429
+ this.writeObjectGzip(value);
430
+ return this;
431
+ } else if (!NO_CONSTRUCTOR.has(constructorId)) {
432
+ this.writeByte(constructorId);
385
433
  }
386
- return this._last;
387
- }
388
- readInt16(signed = true) {
389
- this.assertRead(2);
390
- this._last = this.target[this.offset++] | this.target[this.offset++] << 8;
391
- if (signed) {
392
- this._last = this._last << 16 >> 16;
434
+ switch (constructorId) {
435
+ case CORE_TYPES.Structure: {
436
+ return this.writeStructure(value);
437
+ }
438
+ case CORE_TYPES.Binary: {
439
+ return this.writeBytes(value);
440
+ }
441
+ case CORE_TYPES.GZIP: {
442
+ return this.writeGzip(value);
443
+ }
444
+ case CORE_TYPES.DictIndex: {
445
+ return this.writeLength(value);
446
+ }
447
+ case CORE_TYPES.DictValue: {
448
+ return this.writeString(value);
449
+ }
450
+ case CORE_TYPES.BoolFalse: {
451
+ return this.writeBool(value);
452
+ }
453
+ case CORE_TYPES.BoolTrue: {
454
+ return this.writeBool(value);
455
+ }
456
+ case CORE_TYPES.Date: {
457
+ return this.writeDate(value);
458
+ }
459
+ case CORE_TYPES.Int32: {
460
+ return this.writeInt32(value);
461
+ }
462
+ case CORE_TYPES.Int16: {
463
+ return this.writeInt16(value);
464
+ }
465
+ case CORE_TYPES.Int8: {
466
+ return this.writeInt8(value);
467
+ }
468
+ case CORE_TYPES.UInt32: {
469
+ return this.writeInt32(value, false);
470
+ }
471
+ case CORE_TYPES.UInt16: {
472
+ return this.writeInt16(value, false);
473
+ }
474
+ case CORE_TYPES.UInt8: {
475
+ return this.writeInt8(value, false);
476
+ }
477
+ case CORE_TYPES.Double: {
478
+ return this.writeDouble(value);
479
+ }
480
+ case CORE_TYPES.Float: {
481
+ return this.writeFloat(value);
482
+ }
483
+ case CORE_TYPES.Null: {
484
+ return this.writeNull();
485
+ }
486
+ case CORE_TYPES.String: {
487
+ if (value.length <= 16) {
488
+ this.offset--;
489
+ return this.wireDictionary(value);
490
+ }
491
+ return this.writeString(value);
492
+ }
493
+ case CORE_TYPES.Vector: {
494
+ return this.writeVector(value);
495
+ }
496
+ case CORE_TYPES.Map: {
497
+ return this.writeMap(value);
498
+ }
393
499
  }
394
- return this._last;
500
+ return this;
395
501
  }
396
- readInt8(signed = true) {
397
- this.assertRead(1);
398
- this._last = this.target[this.offset++];
399
- if (signed) {
400
- this._last = this._last << 24 >> 24;
502
+ writeRepeat() {
503
+ if (!this._repeat) {
504
+ this.writeByte(CORE_TYPES.Repeat);
505
+ this._repeat = { count: 0, offset: this.offset };
401
506
  }
402
- return this._last;
403
- }
404
- /**
405
- * Reads a real floating point (4 bytes) value.
406
- * @returns {number}
407
- */
408
- readFloat() {
409
- this.assertRead(4);
410
- int32[0] = this.readInt32();
411
- this._last = float32[0];
412
- return this._last;
507
+ this.offset = this._repeat.offset;
508
+ this._repeat.count++;
509
+ this.writeLength(this._repeat.count);
510
+ return this;
413
511
  }
414
- /**
415
- * Reads a real floating point (8 bytes) value.
416
- * @returns {BigInteger}
417
- */
418
- readDouble() {
419
- this.assertRead(8);
420
- int32[0] = this.readInt32();
421
- int32[1] = this.readInt32();
422
- this._last = float64[0];
423
- return this._last;
512
+ }
513
+
514
+ const CONSTRUCTOR_OPTIONAL = 1644261036;
515
+ const CONSTRUCTOR_OPTIONAL_NULL = 570519212;
516
+ const TYPE_HANDLERS = {
517
+ ["unknown"]: {
518
+ encode: function(value, key) {
519
+ this.writeObject(value[key]);
520
+ },
521
+ decode: function(result, key) {
522
+ result[key] = this.readObject();
523
+ },
524
+ estimatedSizeBytes: 0
525
+ },
526
+ [CORE_TYPES.Map]: {
527
+ encode: function(value, key) {
528
+ this.writeMap(value[key]);
529
+ },
530
+ decode: function(result, key) {
531
+ result[key] = this.readMap(false);
532
+ },
533
+ estimatedSizeBytes: 0
534
+ },
535
+ [CORE_TYPES.Binary]: {
536
+ encode: function(value, key) {
537
+ this.writeBytes(value[key]);
538
+ },
539
+ decode: function(result, key) {
540
+ result[key] = this.readBytes();
541
+ },
542
+ estimatedSizeBytes: 0
543
+ },
544
+ [CORE_TYPES.Vector]: {
545
+ encode: function(value, key) {
546
+ this.writeVector(value[key]);
547
+ },
548
+ decode: function(result, key) {
549
+ result[key] = this.readVector(false);
550
+ },
551
+ estimatedSizeBytes: 0
552
+ },
553
+ [Boolean.name]: {
554
+ encode: function(value, key) {
555
+ this.writeBool(value[key]);
556
+ },
557
+ decode: function(result, key) {
558
+ result[key] = this.readBool();
559
+ },
560
+ estimatedSizeBytes: 1
561
+ },
562
+ [CORE_TYPES.Int8]: {
563
+ encode: function(value, key) {
564
+ this.writeInt8(value[key], true);
565
+ },
566
+ decode: function(result, key) {
567
+ result[key] = this.readInt8(true);
568
+ },
569
+ estimatedSizeBytes: 1
570
+ },
571
+ [CORE_TYPES.Int16]: {
572
+ encode: function(value, key) {
573
+ this.writeInt16(value[key], true);
574
+ },
575
+ decode: function(result, key) {
576
+ result[key] = this.readInt16(true);
577
+ },
578
+ estimatedSizeBytes: 2
579
+ },
580
+ [CORE_TYPES.Int32]: {
581
+ encode: function(value, key) {
582
+ this.writeInt32(value[key], true);
583
+ },
584
+ decode: function(result, key) {
585
+ result[key] = this.readInt32(true);
586
+ },
587
+ estimatedSizeBytes: 4
588
+ },
589
+ [CORE_TYPES.UInt8]: {
590
+ encode: function(value, key) {
591
+ this.writeInt8(value[key], false);
592
+ },
593
+ decode: function(result, key) {
594
+ result[key] = this.readInt8(false);
595
+ },
596
+ estimatedSizeBytes: 1
597
+ },
598
+ [CORE_TYPES.UInt16]: {
599
+ encode: function(value, key) {
600
+ this.writeInt16(value[key], false);
601
+ },
602
+ decode: function(result, key) {
603
+ result[key] = this.readInt16(false);
604
+ },
605
+ estimatedSizeBytes: 2
606
+ },
607
+ [CORE_TYPES.UInt32]: {
608
+ encode: function(value, key) {
609
+ this.writeInt32(value[key], false);
610
+ },
611
+ decode: function(result, key) {
612
+ result[key] = this.readInt32(false);
613
+ },
614
+ estimatedSizeBytes: 4
615
+ },
616
+ [CORE_TYPES.Double]: {
617
+ encode: function(value, key) {
618
+ this.writeDouble(value[key]);
619
+ },
620
+ decode: function(result, key) {
621
+ result[key] = this.readDouble();
622
+ },
623
+ estimatedSizeBytes: 8
624
+ },
625
+ [CORE_TYPES.Date]: {
626
+ encode: function(value, key) {
627
+ this.writeDate(value[key]);
628
+ },
629
+ decode: function(result, key) {
630
+ result[key] = this.readDate();
631
+ },
632
+ estimatedSizeBytes: 8
633
+ },
634
+ [CORE_TYPES.String]: {
635
+ encode: function(value, key) {
636
+ this.writeString(value[key]);
637
+ },
638
+ decode: function(result, key) {
639
+ result[key] = this.readString();
640
+ },
641
+ estimatedSizeBytes: 0
424
642
  }
425
- /**
426
- * Read the given amount of bytes, or -1 to read all remaining.
427
- * @param length {number}
428
- */
429
- assertRead(length) {
430
- if (this.length < this.offset + +length) {
431
- const left = this.target.length - this.offset;
432
- const result = this.target.subarray(this.offset, this.offset + left);
433
- const err = new Error(
434
- `No more data left to read (need ${length}, got ${left}: ${result}); last read ${this._last}`
643
+ };
644
+ TYPE_HANDLERS[Number.name] = TYPE_HANDLERS[CORE_TYPES.Double];
645
+ TYPE_HANDLERS[String.name] = TYPE_HANDLERS[CORE_TYPES.String];
646
+ TYPE_HANDLERS[Object.name] = TYPE_HANDLERS[CORE_TYPES.Map];
647
+ TYPE_HANDLERS[Uint8Array.name] = TYPE_HANDLERS[CORE_TYPES.Binary];
648
+ TYPE_HANDLERS[Array.name] = TYPE_HANDLERS[CORE_TYPES.Vector];
649
+ TYPE_HANDLERS[Date.name] = TYPE_HANDLERS[CORE_TYPES.Date];
650
+ function compileStructure(name, version, properties, checksum) {
651
+ const encodeFns = [];
652
+ const decodeFns = [];
653
+ const structures = [];
654
+ const structureId = crc32(name) >>> 0;
655
+ let estimatedSizeBytes = 1;
656
+ encodeFns.push(function() {
657
+ this.writeByte(version);
658
+ });
659
+ decodeFns.push(function() {
660
+ const ver = this.readByte();
661
+ assert.ok(
662
+ version === ver,
663
+ `Structure ${structureId} version mismatch: expected ${version}, got ${ver}`
664
+ );
665
+ });
666
+ const entries = Object.entries(properties);
667
+ const entriesLength = entries.length;
668
+ for (let i = 0; i < entriesLength; i++) {
669
+ const [key, prop] = entries[i];
670
+ const isRequired = prop.required === true;
671
+ const isArray = Array.isArray(prop.type);
672
+ const propType = Array.isArray(prop.type) ? prop.type[0] : prop.type;
673
+ if (isStructureType(propType)) {
674
+ encodeFns.push(
675
+ createStructureEncoder(key, propType, isRequired, isArray)
435
676
  );
436
- err.incomplete = true;
437
- Error.captureStackTrace(err, this.assertRead);
438
- throw err;
439
- }
440
- }
441
- assertConstructor(constructorId) {
442
- const byte = this.readByte();
443
- if (byte !== constructorId) {
444
- throw new Error(
445
- `Invalid constructor code, expected = ${CORE_TYPES[constructorId]}, got = ${CORE_TYPES[byte] || byte}, offset = ${this.offset - 1}`
677
+ decodeFns.push(createStructureDecoder(key, isRequired, isArray));
678
+ estimatedSizeBytes += propType.estimatedSizeBytes;
679
+ structures.push(propType);
680
+ continue;
681
+ }
682
+ const typeName = propType?.name || (propType === null ? "unknown" : propType);
683
+ const handler = TYPE_HANDLERS[typeName];
684
+ if (handler) {
685
+ encodeFns.push(
686
+ createBoundEncoder(handler.encode, key, isRequired, isArray)
687
+ );
688
+ decodeFns.push(
689
+ createBoundDecoder(handler.decode, key, isRequired, isArray)
690
+ );
691
+ estimatedSizeBytes += handler.estimatedSizeBytes;
692
+ } else {
693
+ throw new Error(`Unsupported property type: ${typeName || "unknown"}`);
694
+ }
695
+ }
696
+ if (checksum) {
697
+ estimatedSizeBytes += 4;
698
+ encodeFns.push(function() {
699
+ this.writeChecksum(false);
700
+ });
701
+ decodeFns.push(function() {
702
+ this.readChecksum(false);
703
+ });
704
+ }
705
+ const compiled = {
706
+ id: structureId,
707
+ encodeFns,
708
+ decodeFns,
709
+ structures,
710
+ estimatedSizeBytes
711
+ };
712
+ return compiled;
713
+ }
714
+ function isStructureType(type) {
715
+ return type?.prototype && Structure.prototype.isPrototypeOf(type.prototype);
716
+ }
717
+ function createStructureEncoder(key, StructureCtor, isRequired, isArray) {
718
+ return function(value) {
719
+ const hasValue = value[key] !== void 0 && value[key] !== null;
720
+ if (!hasValue) {
721
+ assert.ok(!isRequired, `Required property "${key}" is missing or null`);
722
+ if (value[key] === null) {
723
+ this.writeInt32(CONSTRUCTOR_OPTIONAL_NULL);
724
+ } else {
725
+ this.writeInt32(CONSTRUCTOR_OPTIONAL);
726
+ }
727
+ } else if (isArray) {
728
+ const arr = value[key];
729
+ assert.array(arr, `Expected property "${key}" to be array.`);
730
+ this.writeLength(arr.length);
731
+ for (let idx = 0; idx < arr.length; idx++) {
732
+ this.writeStructure(
733
+ arr[idx] instanceof Structure ? arr[idx] : new StructureCtor(arr[idx])
734
+ );
735
+ }
736
+ } else {
737
+ this.writeStructure(
738
+ value[key] instanceof Structure ? value[key] : new StructureCtor(value[key])
446
739
  );
447
740
  }
448
- }
449
- /**
450
- * Gets the byte array representing the current buffer as a whole.
451
- */
452
- getBuffer() {
453
- return this.target;
454
- }
455
- readNull() {
456
- const value = this.readByte();
457
- if (value === CORE_TYPES.Null) {
458
- return null;
459
- }
460
- throw new Error(`Invalid boolean code ${value.toString(16)}`);
461
- }
462
- readLength() {
463
- const firstByte = this.readByte();
464
- if (firstByte === 254) {
465
- return this.readByte() | this.readByte() << 8 | this.readByte() << 16;
741
+ };
742
+ }
743
+ function createStructureDecoder(key, isRequired, isArray) {
744
+ return function(result) {
745
+ let shouldRead = true;
746
+ if (!isRequired) {
747
+ shouldRead = !readMaybeInt32(this, CONSTRUCTOR_OPTIONAL);
748
+ if (shouldRead && readMaybeInt32(this, CONSTRUCTOR_OPTIONAL_NULL)) {
749
+ result[key] = null;
750
+ return;
751
+ }
466
752
  }
467
- return firstByte;
468
- }
469
- readAll() {
470
- const result = [];
471
- while (this.length > this.offset) {
472
- result.push(this.readObject());
753
+ if (shouldRead) {
754
+ if (isArray) {
755
+ const length = this.readLength();
756
+ const arrResult = Array.from({ length });
757
+ for (let idx = 0; idx < length; idx++) {
758
+ arrResult[idx] = this.readStructure(false);
759
+ }
760
+ result[key] = arrResult;
761
+ } else {
762
+ result[key] = this.readStructure(false);
763
+ }
473
764
  }
474
- return result;
475
- }
476
- readBytes() {
477
- const length = this.readLength();
478
- this.assertRead(length);
479
- const bytes = this.target.subarray(this.offset, this.offset + length);
480
- this.offset += bytes.length;
481
- this._last = bytes;
482
- return bytes;
483
- }
484
- /**
485
- * Reads encoded string.
486
- */
487
- readString() {
488
- const length = this.readLength();
489
- this.assertRead(length);
490
- const result = utf8Read(this.target, length, this.offset);
491
- this.offset += length;
492
- this._last = result;
493
- return result;
494
- }
495
- /**
496
- * Reads a boolean value.
497
- */
498
- readBool() {
499
- const value = this.readByte();
500
- if (value === CORE_TYPES.BoolTrue) {
501
- return true;
502
- } else if (value === CORE_TYPES.BoolFalse) {
503
- return false;
504
- } else {
505
- throw new Error(`Invalid boolean code ${value.toString(16)}`);
765
+ };
766
+ }
767
+ function readMaybeInt32(reader, expectedValue) {
768
+ let result = false;
769
+ if (reader.length >= reader.offset + 4) {
770
+ result = reader.readInt32() === expectedValue;
771
+ if (!result) {
772
+ reader.offset -= 4;
506
773
  }
507
774
  }
508
- /**
509
- * Reads and converts Unix time
510
- * into a Javascript {Date} object.
511
- */
512
- readDate() {
513
- const value = this.readDouble();
514
- return new Date(value);
515
- }
516
- /**
517
- * Reads a object.
518
- */
519
- readObject() {
520
- if (this._repeat) {
521
- if (this._repeat.pool > 0) {
522
- --this._repeat.pool;
523
- return this._repeat.value;
775
+ return result;
776
+ }
777
+ function createBoundEncoder(encodeFn, key, isRequired, isArray) {
778
+ return function(value) {
779
+ const hasValue = value[key] !== void 0 && value[key] !== null;
780
+ if (!hasValue) {
781
+ assert.ok(!isRequired, `Required property "${key}" is missing or null`);
782
+ if (value[key] === null) {
783
+ this.writeInt32(CONSTRUCTOR_OPTIONAL_NULL);
524
784
  } else {
525
- this._repeat = void 0;
785
+ this.writeInt32(CONSTRUCTOR_OPTIONAL);
786
+ }
787
+ } else if (isArray) {
788
+ const arr = value[key];
789
+ assert.array(arr, `Expected property "${key}" to be array.`);
790
+ this.writeLength(arr.length);
791
+ for (let idx = 0; idx < arr.length; idx++) {
792
+ encodeFn.call(this, arr, idx);
526
793
  }
527
- }
528
- const constructorId = this.readByte();
529
- const ext = this.extensions.get(constructorId);
530
- let value;
531
- if (ext) {
532
- value = ext.decode.call(this);
533
794
  } else {
534
- value = this._lastObject = this.readCore(constructorId);
795
+ encodeFn.call(this, value, key);
535
796
  }
536
- return value;
537
- }
538
- readObjectGzip() {
539
- const bytes = this.readGzip();
540
- const reader = new BinaryReader(bytes);
541
- reader.extensions = this.extensions;
542
- reader.dictionary = this.dictionary;
543
- reader.dictionaryExtended = this.dictionaryExtended;
544
- return reader.readObject();
545
- }
546
- readGzip() {
547
- return pako.inflateRaw(this.readBytes());
548
- }
549
- readCore(constructorId) {
550
- switch (constructorId) {
551
- case CORE_TYPES.None:
552
- return this.readObject();
553
- case CORE_TYPES.GZIP:
554
- return this.readObjectGzip();
555
- case CORE_TYPES.BoolTrue:
556
- return true;
557
- case CORE_TYPES.BoolFalse:
558
- return false;
559
- case CORE_TYPES.Vector:
560
- return this.readVector(false);
561
- case CORE_TYPES.VectorDynamic:
562
- return this.readVectorDynamic(false);
563
- case CORE_TYPES.Null:
564
- return null;
565
- case CORE_TYPES.Binary:
566
- return this.readBytes();
567
- case CORE_TYPES.String:
568
- return this.readString();
569
- case CORE_TYPES.Date:
570
- return this.readDate();
571
- case CORE_TYPES.Int32:
572
- return this.readInt32();
573
- case CORE_TYPES.Int16:
574
- return this.readInt16();
575
- case CORE_TYPES.Int8:
576
- return this.readInt8();
577
- case CORE_TYPES.UInt32:
578
- return this.readInt32(false);
579
- case CORE_TYPES.UInt16:
580
- return this.readInt16(false);
581
- case CORE_TYPES.UInt8:
582
- return this.readInt8(false);
583
- case CORE_TYPES.Float:
584
- return this.readFloat();
585
- case CORE_TYPES.Double:
586
- return this.readDouble();
587
- case CORE_TYPES.Map:
588
- return this.readMap(false);
589
- case CORE_TYPES.Checksum:
590
- return void this.readChecksum(false);
591
- case CORE_TYPES.DictIndex: {
592
- const idx = this.readLength();
593
- return this.getDictionaryValue(idx);
797
+ };
798
+ }
799
+ function createBoundDecoder(decodeFn, key, isRequired, isArray) {
800
+ return function(result) {
801
+ let shouldRead = true;
802
+ if (!isRequired) {
803
+ shouldRead = !readMaybeInt32(this, CONSTRUCTOR_OPTIONAL);
804
+ if (shouldRead && readMaybeInt32(this, CONSTRUCTOR_OPTIONAL_NULL)) {
805
+ result[key] = null;
806
+ return;
594
807
  }
595
- case CORE_TYPES.DictValue: {
596
- const value = this.readString();
597
- this.dictionaryExtended.maybeInsert(value);
598
- return value;
808
+ }
809
+ if (shouldRead) {
810
+ if (isArray) {
811
+ const length = this.readLength();
812
+ const arrResult = Array.from({ length });
813
+ for (let idx = 0; idx < length; idx++) {
814
+ decodeFn.call(this, arrResult, idx);
815
+ }
816
+ result[key] = arrResult;
817
+ } else {
818
+ decodeFn.call(this, result, key);
599
819
  }
600
- case CORE_TYPES.Repeat: {
601
- const size = this.readLength();
602
- this._repeat = { pool: size - 1, value: this._lastObject };
603
- return this._lastObject;
820
+ }
821
+ };
822
+ }
823
+ function defineStructure({
824
+ name,
825
+ properties,
826
+ version,
827
+ checksum = false
828
+ }) {
829
+ const compiled = compileStructure(name, version, properties, checksum);
830
+ return class DefinedStructure extends Structure {
831
+ static estimatedSizeBytes = compiled.estimatedSizeBytes;
832
+ static structures = compiled.structures;
833
+ static extension = {
834
+ token: compiled.id,
835
+ encode(value) {
836
+ const fns = compiled.encodeFns;
837
+ const length = fns.length;
838
+ for (let i = 0; i < length; i++) {
839
+ fns[i].call(this, value);
840
+ }
841
+ },
842
+ decode() {
843
+ const result = {};
844
+ const fns = compiled.decodeFns;
845
+ const length = fns.length;
846
+ for (let i = 0; i < length; i++) {
847
+ fns[i].call(this, result);
848
+ }
849
+ return result;
604
850
  }
605
- }
606
- throw new Error(
607
- `Invalid constructor = ${CORE_TYPES[constructorId] || constructorId}, offset = ${this.offset - 1}`
608
- );
851
+ };
852
+ };
853
+ }
854
+ class Structure {
855
+ value;
856
+ constructor(value) {
857
+ this.value = value;
858
+ }
859
+ toBuffer(options) {
860
+ const ctor = this.constructor;
861
+ const writer = new BinaryWriter(options);
862
+ ctor.extension.encode.call(writer, this.value);
863
+ return writer.getBuffer();
864
+ }
865
+ static fromBuffer(buffer, options = {}) {
866
+ const reader = new BinaryReader(buffer, {
867
+ ...options,
868
+ structures: options.structures ? this.structures.concat(options.structures) : this.structures
869
+ });
870
+ return this.extension.decode.call(reader);
871
+ }
872
+ static estimatedSizeBytes = -1;
873
+ static structures = [];
874
+ static extension = {
875
+ token: CORE_TYPES.Binary,
876
+ encode: noop$1,
877
+ decode: noop$1
878
+ };
879
+ }
880
+
881
+ const encoder = new TextEncoder();
882
+ const decoder = new TextDecoder();
883
+ const fromCharCode = String.fromCharCode;
884
+ const int32 = new Int32Array(2);
885
+ const float32 = new Float32Array(int32.buffer);
886
+ const float64 = new Float64Array(int32.buffer);
887
+ function byteArrayAllocate(length) {
888
+ return new Uint8Array(length);
889
+ }
890
+ function coreType(value) {
891
+ if (value instanceof Structure) {
892
+ return CORE_TYPES.Structure;
893
+ } else if (value instanceof Uint8Array) {
894
+ return CORE_TYPES.Binary;
609
895
  }
610
- getDictionaryValue(index) {
611
- let value = null;
612
- if (this.dictionary) {
613
- value = this.dictionary.getValue(index);
896
+ switch (typeof value) {
897
+ case "string": {
898
+ return CORE_TYPES.String;
614
899
  }
615
- if (value === null) {
616
- value = this.dictionaryExtended.getValue(index);
900
+ case "boolean": {
901
+ return value ? CORE_TYPES.BoolTrue : CORE_TYPES.BoolFalse;
617
902
  }
618
- return value;
619
- }
620
- readDictionary() {
621
- const constructorId = this.readByte();
622
- let key = null;
623
- switch (constructorId) {
624
- case CORE_TYPES.DictIndex: {
625
- const idx = this.readLength();
626
- key = this.getDictionaryValue(idx);
627
- break;
903
+ case "number": {
904
+ if (Math.trunc(value) === value) {
905
+ if (value >= 0 && value <= 255) {
906
+ return CORE_TYPES.UInt8;
907
+ } else if (value >= 0 && value <= 65535) {
908
+ return CORE_TYPES.UInt16;
909
+ } else if (value >= 0 && value <= 4294967295) {
910
+ return CORE_TYPES.UInt32;
911
+ } else if (value >= -128 && value <= 127) {
912
+ return CORE_TYPES.Int8;
913
+ } else if (value >= -32768 && value <= 32767) {
914
+ return CORE_TYPES.Int16;
915
+ } else if (value >= -2147483648 && value <= 2147483647) {
916
+ return CORE_TYPES.Int32;
917
+ }
628
918
  }
629
- case CORE_TYPES.DictValue: {
630
- key = this.readString();
631
- this.dictionaryExtended.maybeInsert(key);
632
- break;
919
+ return CORE_TYPES.Double;
920
+ }
921
+ case "object": {
922
+ if (value === null) return CORE_TYPES.Null;
923
+ if (value instanceof Date) {
924
+ return CORE_TYPES.Date;
633
925
  }
634
- case CORE_TYPES.None: {
635
- key = null;
636
- break;
926
+ if (Array.isArray(value)) {
927
+ return CORE_TYPES.Vector;
637
928
  }
638
- default: {
639
- this.seek(-1);
929
+ if (isPlainObject(value)) {
930
+ return CORE_TYPES.Map;
640
931
  }
641
932
  }
642
- return key;
643
933
  }
644
- readMap(checkConstructor = true) {
645
- if (checkConstructor) {
646
- this.assertConstructor(CORE_TYPES.Map);
934
+ return CORE_TYPES.None;
935
+ }
936
+ function utf8Read(target, length, offset) {
937
+ let result;
938
+ if (length < 16) {
939
+ if (result = utf8ReadShort(target, length, offset)) return result;
940
+ }
941
+ if (length > 64 && decoder)
942
+ return decoder.decode(target.subarray(offset, offset += length));
943
+ const end = offset + length;
944
+ const units = [];
945
+ result = "";
946
+ while (offset < end) {
947
+ const byte1 = target[offset++];
948
+ if ((byte1 & 128) === 0) {
949
+ units.push(byte1);
950
+ } else if ((byte1 & 224) === 192) {
951
+ const byte2 = target[offset++] & 63;
952
+ units.push((byte1 & 31) << 6 | byte2);
953
+ } else if ((byte1 & 240) === 224) {
954
+ const byte2 = target[offset++] & 63;
955
+ const byte3 = target[offset++] & 63;
956
+ units.push((byte1 & 31) << 12 | byte2 << 6 | byte3);
957
+ } else if ((byte1 & 248) === 240) {
958
+ const byte2 = target[offset++] & 63;
959
+ const byte3 = target[offset++] & 63;
960
+ const byte4 = target[offset++] & 63;
961
+ let unit = (byte1 & 7) << 18 | byte2 << 12 | byte3 << 6 | byte4;
962
+ if (unit > 65535) {
963
+ unit -= 65536;
964
+ units.push(unit >>> 10 & 1023 | 55296);
965
+ unit = 56320 | unit & 1023;
966
+ }
967
+ units.push(unit);
968
+ } else {
969
+ units.push(byte1);
647
970
  }
648
- const temp = {};
649
- let key = this.readDictionary();
650
- while (key !== null) {
651
- temp[key] = this.readObject();
652
- key = this.readDictionary();
971
+ if (units.length >= 4096) {
972
+ result += fromCharCode.apply(String, units);
973
+ units.length = 0;
653
974
  }
654
- return temp;
655
975
  }
656
- decode(value) {
657
- this.target = value;
658
- this._last = void 0;
659
- this._lastObject = void 0;
660
- this._repeat = void 0;
661
- this.offset = 0;
662
- this._checksumOffset = 0;
663
- this.length = value.length;
664
- return this.readObject();
976
+ if (units.length > 0) {
977
+ result += fromCharCode.apply(String, units);
665
978
  }
666
- /**
667
- * Reads a vector (a list) of objects.
668
- */
669
- readVector(checkConstructor = true) {
670
- if (checkConstructor) {
671
- this.assertConstructor(CORE_TYPES.Vector);
672
- }
673
- const count = this.readLength();
674
- const temp = [];
675
- for (let i = 0; i < count; i++) {
676
- temp.push(this.readObject());
979
+ return result;
980
+ }
981
+ function utf8ReadShort(target, length, offset) {
982
+ if (length < 4) {
983
+ if (length < 2) {
984
+ if (length === 0) return "";
985
+ else {
986
+ let a = target[offset++];
987
+ if ((a & 128) > 1) {
988
+ offset -= 1;
989
+ return;
990
+ }
991
+ return fromCharCode(a);
992
+ }
993
+ } else {
994
+ let a = target[offset++];
995
+ let b = target[offset++];
996
+ if ((a & 128) > 0 || (b & 128) > 0) {
997
+ offset -= 2;
998
+ return;
999
+ }
1000
+ if (length < 3) return fromCharCode(a, b);
1001
+ let c = target[offset++];
1002
+ if ((c & 128) > 0) {
1003
+ offset -= 3;
1004
+ return;
1005
+ }
1006
+ return fromCharCode(a, b, c);
677
1007
  }
678
- return temp;
679
- }
680
- /**
681
- * Reads a vector (a list) of objects.
682
- */
683
- readVectorDynamic(checkConstructor = true) {
684
- if (checkConstructor) {
685
- this.assertConstructor(CORE_TYPES.VectorDynamic);
1008
+ } else {
1009
+ let a = target[offset++];
1010
+ let b = target[offset++];
1011
+ let c = target[offset++];
1012
+ let d = target[offset++];
1013
+ if ((a & 128) > 0 || (b & 128) > 0 || (c & 128) > 0 || (d & 128) > 0) {
1014
+ offset -= 4;
1015
+ return;
686
1016
  }
687
- const temp = [];
688
- let complete = false;
689
- while (this.length > this.offset) {
690
- const constructorId = this.readByte();
691
- if (constructorId === CORE_TYPES.None) {
692
- complete = true;
693
- break;
1017
+ if (length < 6) {
1018
+ if (length === 4) return fromCharCode(a, b, c, d);
1019
+ else {
1020
+ let e = target[offset++];
1021
+ if ((e & 128) > 0) {
1022
+ offset -= 5;
1023
+ return;
1024
+ }
1025
+ return fromCharCode(a, b, c, d, e);
694
1026
  }
695
- const ext = this.extensions.get(constructorId);
696
- let value;
697
- if (ext) {
698
- value = ext.decode.call(this);
1027
+ } else if (length < 8) {
1028
+ let e = target[offset++];
1029
+ let f = target[offset++];
1030
+ if ((e & 128) > 0 || (f & 128) > 0) {
1031
+ offset -= 6;
1032
+ return;
1033
+ }
1034
+ if (length < 7) return fromCharCode(a, b, c, d, e, f);
1035
+ let g = target[offset++];
1036
+ if ((g & 128) > 0) {
1037
+ offset -= 7;
1038
+ return;
1039
+ }
1040
+ return fromCharCode(a, b, c, d, e, f, g);
1041
+ } else {
1042
+ let e = target[offset++];
1043
+ let f = target[offset++];
1044
+ let g = target[offset++];
1045
+ let h = target[offset++];
1046
+ if ((e & 128) > 0 || (f & 128) > 0 || (g & 128) > 0 || (h & 128) > 0) {
1047
+ offset -= 8;
1048
+ return;
1049
+ }
1050
+ if (length < 10) {
1051
+ if (length === 8) return fromCharCode(a, b, c, d, e, f, g, h);
1052
+ else {
1053
+ let i = target[offset++];
1054
+ if ((i & 128) > 0) {
1055
+ offset -= 9;
1056
+ return;
1057
+ }
1058
+ return fromCharCode(a, b, c, d, e, f, g, h, i);
1059
+ }
1060
+ } else if (length < 12) {
1061
+ let i = target[offset++];
1062
+ let j = target[offset++];
1063
+ if ((i & 128) > 0 || (j & 128) > 0) {
1064
+ offset -= 10;
1065
+ return;
1066
+ }
1067
+ if (length < 11) return fromCharCode(a, b, c, d, e, f, g, h, i, j);
1068
+ let k = target[offset++];
1069
+ if ((k & 128) > 0) {
1070
+ offset -= 11;
1071
+ return;
1072
+ }
1073
+ return fromCharCode(a, b, c, d, e, f, g, h, i, j, k);
699
1074
  } else {
700
- value = this.readCore(constructorId);
1075
+ let i = target[offset++];
1076
+ let j = target[offset++];
1077
+ let k = target[offset++];
1078
+ let l = target[offset++];
1079
+ if ((i & 128) > 0 || (j & 128) > 0 || (k & 128) > 0 || (l & 128) > 0) {
1080
+ offset -= 12;
1081
+ return;
1082
+ }
1083
+ if (length < 14) {
1084
+ if (length === 12)
1085
+ return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l);
1086
+ else {
1087
+ let m = target[offset++];
1088
+ if ((m & 128) > 0) {
1089
+ offset -= 13;
1090
+ return;
1091
+ }
1092
+ return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m);
1093
+ }
1094
+ } else {
1095
+ let m = target[offset++];
1096
+ let n = target[offset++];
1097
+ if ((m & 128) > 0 || (n & 128) > 0) {
1098
+ offset -= 14;
1099
+ return;
1100
+ }
1101
+ if (length < 15)
1102
+ return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n);
1103
+ let o = target[offset++];
1104
+ if ((o & 128) > 0) {
1105
+ offset -= 15;
1106
+ return;
1107
+ }
1108
+ return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
1109
+ }
701
1110
  }
702
- temp.push(value);
703
- }
704
- if (!complete) {
705
- const err = new Error(`DynamicVector incomplete.`);
706
- err.incomplete = true;
707
- Error.captureStackTrace(err, this.readDictionary);
708
- throw err;
709
1111
  }
710
- this._last = temp;
711
- return temp;
712
1112
  }
713
- readChecksum(checkConstructor = true) {
714
- const offset = this.offset;
715
- if (checkConstructor) {
716
- this.assertConstructor(CORE_TYPES.Checksum);
717
- }
718
- const bytes = this.target.slice(this._checksumOffset, offset);
719
- const checksum = this.readLength();
720
- let sum = 0;
721
- for (const val of bytes) {
722
- sum += val;
723
- }
724
- if (checksum - sum !== 0) {
725
- throw new Error(
726
- `Invalid checksum = ${checksum - sum}, offset = ${offset}`
727
- );
1113
+ }
1114
+ const utf8Write = function(target, value, offset) {
1115
+ return value.length < 64 ? utf8WriteShort(target, value, offset) : encoder.encodeInto(value, target.subarray(offset)).written;
1116
+ };
1117
+ const utf8WriteShort = (target, value, offset) => {
1118
+ let i, c1, c2, strPosition = offset;
1119
+ const strLength = value.length;
1120
+ for (i = 0; i < strLength; i++) {
1121
+ c1 = value.charCodeAt(i);
1122
+ if (c1 < 128) {
1123
+ target[strPosition++] = c1;
1124
+ } else if (c1 < 2048) {
1125
+ target[strPosition++] = c1 >> 6 | 192;
1126
+ target[strPosition++] = c1 & 63 | 128;
1127
+ } else if ((c1 & 64512) === 55296 && ((c2 = value.charCodeAt(i + 1)) & 64512) === 56320) {
1128
+ c1 = 65536 + ((c1 & 1023) << 10) + (c2 & 1023);
1129
+ i++;
1130
+ target[strPosition++] = c1 >> 18 | 240;
1131
+ target[strPosition++] = c1 >> 12 & 63 | 128;
1132
+ target[strPosition++] = c1 >> 6 & 63 | 128;
1133
+ target[strPosition++] = c1 & 63 | 128;
1134
+ } else {
1135
+ target[strPosition++] = c1 >> 12 | 224;
1136
+ target[strPosition++] = c1 >> 6 & 63 | 128;
1137
+ target[strPosition++] = c1 & 63 | 128;
728
1138
  }
729
- this._checksumOffset = this.offset;
730
- }
731
- /**
732
- * Tells the current position on the stream.
733
- */
734
- tellPosition() {
735
- return this.offset;
736
- }
737
- /**
738
- * Sets the current position on the stream.
739
- */
740
- setPosition(position) {
741
- this.offset = position;
742
- }
743
- /**
744
- * Seeks the stream position given an offset from the current position.
745
- * The offset may be negative.
746
- */
747
- seek(offset) {
748
- this.offset += offset;
749
1139
  }
750
- }
1140
+ return strPosition - offset;
1141
+ };
751
1142
 
752
- const noop = Symbol();
753
- const NO_CONSTRUCTOR = /* @__PURE__ */ new Set([
754
- CORE_TYPES.BoolFalse,
755
- CORE_TYPES.BoolTrue,
756
- CORE_TYPES.Null
757
- ]);
758
- const SUPPORT_COMPRESSION = /* @__PURE__ */ new Set([CORE_TYPES.String]);
759
- class BinaryWriter {
760
- withGzip;
1143
+ const NOOP_DICTIONARY = new Dictionary();
1144
+ class BinaryReader {
761
1145
  target;
1146
+ _last;
1147
+ _lastObject;
762
1148
  dictionary;
763
1149
  dictionaryExtended;
764
1150
  extensions;
765
- _last = noop;
766
- _checksumOffset;
1151
+ structures;
767
1152
  _repeat;
1153
+ _checksumOffset;
768
1154
  offset;
769
- constructor(options) {
1155
+ length;
1156
+ /**
1157
+ * Small utility class to read binary data.
1158
+ */
1159
+ constructor(data, {
1160
+ dictionary = NOOP_DICTIONARY,
1161
+ extensions,
1162
+ structures
1163
+ } = {}) {
1164
+ this.target = data;
770
1165
  this.offset = 0;
771
1166
  this._checksumOffset = 0;
1167
+ this.length = data.length;
772
1168
  this.extensions = /* @__PURE__ */ new Map();
773
- this.withGzip = !!options && !!options.gzip;
774
- this.target = byteArrayAllocate(8192);
775
- if (options && options.extensions) {
776
- options.extensions.forEach((ext) => {
1169
+ this.structures = /* @__PURE__ */ new Map();
1170
+ if (extensions) {
1171
+ for (const ext of extensions) {
777
1172
  this.extensions.set(ext.token, ext);
778
- });
1173
+ }
1174
+ }
1175
+ if (structures) {
1176
+ for (const struct of structures) {
1177
+ this.structures.set(struct.extension.token, struct);
1178
+ }
779
1179
  }
780
- if (!options) {
781
- this.dictionary = new Dictionary();
782
- } else if (options.dictionary instanceof Dictionary) {
783
- this.dictionary = options.dictionary;
784
- } else if (Array.isArray(options.dictionary)) {
785
- this.dictionary = new Dictionary(options.dictionary);
1180
+ if (Array.isArray(dictionary)) {
1181
+ this.dictionary = new Dictionary(dictionary);
786
1182
  } else {
787
- this.dictionary = new Dictionary();
1183
+ this.dictionary = dictionary;
788
1184
  }
789
1185
  this.dictionaryExtended = new Dictionary(void 0, this.dictionary.size);
790
1186
  }
791
- allocate(size) {
792
- const position = this.offset + size;
793
- if (this.safeEnd < position) {
794
- this.makeRoom(position);
1187
+ readByte() {
1188
+ this.assertRead(1);
1189
+ this._last = this.target[this.offset++];
1190
+ return this._last;
1191
+ }
1192
+ readInt32(signed = true) {
1193
+ this.assertRead(4);
1194
+ this._last = this.target[this.offset++] | this.target[this.offset++] << 8 | this.target[this.offset++] << 16 | this.target[this.offset++] << 24;
1195
+ if (!signed) {
1196
+ this._last = this._last >>> 0;
795
1197
  }
796
- return this;
1198
+ return this._last;
797
1199
  }
798
- makeRoom(end) {
799
- let start = 0;
800
- let newSize = 0;
801
- let target = this.target;
802
- if (end > 16777216) {
803
- if (end - start > MAX_BUFFER_SIZE)
804
- throw new Error(
805
- "Packed buffer would be larger than maximum buffer size"
806
- );
807
- newSize = Math.min(
808
- MAX_BUFFER_SIZE,
809
- Math.round(
810
- Math.max((end - start) * (end > 67108864 ? 1.25 : 2), 4194304) / 4096
811
- ) * 4096
812
- );
813
- } else {
814
- newSize = (Math.max(end - start << 2, target.length - 1) >> 12) + 1 << 12;
1200
+ readInt16(signed = true) {
1201
+ this.assertRead(2);
1202
+ this._last = this.target[this.offset++] | this.target[this.offset++] << 8;
1203
+ if (signed) {
1204
+ this._last = this._last << 16 >> 16;
815
1205
  }
816
- const newBuffer = byteArrayAllocate(newSize);
817
- end = Math.min(end, target.length);
818
- newBuffer.set(target.slice(start, end));
819
- this.target = newBuffer;
1206
+ return this._last;
820
1207
  }
821
- get safeEnd() {
822
- return this.target.length - 10;
1208
+ readInt8(signed = true) {
1209
+ this.assertRead(1);
1210
+ this._last = this.target[this.offset++];
1211
+ if (signed) {
1212
+ this._last = this._last << 24 >> 24;
1213
+ }
1214
+ return this._last;
823
1215
  }
824
- getBuffer() {
825
- return this.target.subarray(0, this.offset);
1216
+ /**
1217
+ * Reads a real floating point (4 bytes) value.
1218
+ * @returns {number}
1219
+ */
1220
+ readFloat() {
1221
+ this.assertRead(4);
1222
+ int32[0] = this.readInt32();
1223
+ this._last = float32[0];
1224
+ return this._last;
826
1225
  }
827
- writeByte(value) {
828
- this.allocate(1);
829
- this.target[this.offset++] = value;
830
- return this;
1226
+ /**
1227
+ * Reads a real floating point (8 bytes) value.
1228
+ * @returns {BigInteger}
1229
+ */
1230
+ readDouble() {
1231
+ this.assertRead(8);
1232
+ int32[0] = this.readInt32();
1233
+ int32[1] = this.readInt32();
1234
+ this._last = float64[0];
1235
+ return this._last;
831
1236
  }
832
- writeBool(value) {
833
- if (value) {
834
- this.writeByte(CORE_TYPES.BoolTrue);
835
- } else {
836
- this.writeByte(CORE_TYPES.BoolFalse);
1237
+ /**
1238
+ * Throws error if provided length cannot be read from buffer
1239
+ * @param length {number}
1240
+ */
1241
+ assertRead(length) {
1242
+ if (this.length < this.offset + +length) {
1243
+ const left = this.target.length - this.offset;
1244
+ const result = this.target.subarray(this.offset, this.offset + left);
1245
+ const err = new Error(
1246
+ `No more data left to read (need ${length}, got ${left}: ${result}); last read ${this._last}`
1247
+ );
1248
+ err.incomplete = true;
1249
+ Error.captureStackTrace(err, this.assertRead);
1250
+ throw err;
837
1251
  }
838
- return this;
839
1252
  }
840
- writeNull() {
841
- this.writeByte(CORE_TYPES.Null);
842
- return this;
1253
+ assertConstructor(constructorId) {
1254
+ const byte = this.readByte();
1255
+ if (byte !== constructorId) {
1256
+ throw new Error(
1257
+ `Invalid constructor code, expected = ${CORE_TYPES[constructorId]}, got = ${CORE_TYPES[byte] || byte}, offset = ${this.offset - 1}`
1258
+ );
1259
+ }
843
1260
  }
844
- writeInt32(value, signed = true) {
845
- this.allocate(4);
846
- if (signed) {
847
- this.target[this.offset++] = value;
848
- this.target[this.offset++] = value >> 8;
849
- this.target[this.offset++] = value >> 16;
850
- this.target[this.offset++] = value >> 24;
851
- } else {
852
- this.target[this.offset++] = value;
853
- this.target[this.offset++] = value >> 8;
854
- this.target[this.offset++] = value >> 16;
855
- this.target[this.offset++] = value >> 24;
1261
+ /**
1262
+ * Gets the byte array representing the current buffer as a whole.
1263
+ */
1264
+ getBuffer() {
1265
+ return this.target;
1266
+ }
1267
+ readNull() {
1268
+ const value = this.readByte();
1269
+ if (value === CORE_TYPES.Null) {
1270
+ return null;
856
1271
  }
857
- return this;
1272
+ throw new Error(`Invalid boolean code ${value.toString(16)}`);
858
1273
  }
859
- writeInt16(value, signed = true) {
860
- this.allocate(2);
861
- if (signed) {
862
- this.target[this.offset++] = value;
863
- this.target[this.offset++] = value >> 8;
864
- } else {
865
- this.target[this.offset++] = value;
866
- this.target[this.offset++] = value >> 8;
1274
+ readLength() {
1275
+ const firstByte = this.readByte();
1276
+ if (firstByte === 254) {
1277
+ return this.readByte() | this.readByte() << 8 | this.readByte() << 16;
867
1278
  }
868
- return this;
1279
+ return firstByte;
869
1280
  }
870
- writeInt8(value, signed = true) {
871
- this.allocate(1);
872
- this.target[this.offset++] = value;
873
- return this;
1281
+ readAll() {
1282
+ const result = [];
1283
+ while (this.length > this.offset) {
1284
+ result.push(this.readObject());
1285
+ }
1286
+ return result;
874
1287
  }
875
- writeFloat(value) {
876
- this.allocate(4);
877
- float32[0] = value;
878
- this.writeInt32(int32[0]);
879
- return this;
1288
+ readBytes() {
1289
+ const length = this.readLength();
1290
+ this.assertRead(length);
1291
+ const bytes = this.target.subarray(this.offset, this.offset + length);
1292
+ this.offset += bytes.length;
1293
+ this._last = bytes;
1294
+ return bytes;
880
1295
  }
881
- writeDouble(value) {
882
- this.allocate(8);
883
- float64[0] = value;
884
- this.writeInt32(int32[0], false);
885
- this.writeInt32(int32[1], false);
886
- return this;
1296
+ /**
1297
+ * Reads encoded string.
1298
+ */
1299
+ readString() {
1300
+ const length = this.readLength();
1301
+ this.assertRead(length);
1302
+ const result = utf8Read(this.target, length, this.offset);
1303
+ this.offset += length;
1304
+ this._last = result;
1305
+ return result;
887
1306
  }
888
- writeDate(value) {
889
- let timestamp = 0;
890
- if (value instanceof Date) {
891
- timestamp = value.getTime();
892
- } else if (typeof value === "number") {
893
- timestamp = value;
1307
+ /**
1308
+ * Reads a boolean value.
1309
+ */
1310
+ readBool() {
1311
+ const value = this.readByte();
1312
+ if (value === CORE_TYPES.BoolTrue) {
1313
+ return true;
1314
+ } else if (value === CORE_TYPES.BoolFalse) {
1315
+ return false;
1316
+ } else {
1317
+ throw new Error(`Invalid boolean code ${value.toString(16)}`);
894
1318
  }
895
- this.writeDouble(timestamp);
896
- return this;
897
1319
  }
898
- writeString(value) {
899
- const strLength = value.length;
900
- let start = this.offset;
901
- let require = strLength << 2;
902
- if (require < 254) {
903
- require += 1;
904
- this.offset += 1;
905
- } else {
906
- require += 4;
907
- this.offset += 4;
1320
+ /**
1321
+ * Reads and converts Unix time
1322
+ * into a Javascript {Date} object.
1323
+ */
1324
+ readDate() {
1325
+ const value = this.readDouble();
1326
+ return new Date(value);
1327
+ }
1328
+ readStructure(checkConstructor = true) {
1329
+ if (checkConstructor) {
1330
+ this.assertConstructor(CORE_TYPES.Structure);
908
1331
  }
909
- this.allocate(require);
910
- const bytes = utf8Write(this.target, value, this.offset);
911
- if (require < 254) {
912
- this.target[start++] = bytes;
913
- } else {
914
- this.target[start++] = 254;
915
- this.target[start++] = bytes % 256;
916
- this.target[start++] = (bytes >> 8) % 256;
917
- this.target[start++] = (bytes >> 16) % 256;
1332
+ const structureId = this.readInt32(false);
1333
+ const struct = this.structures.get(structureId);
1334
+ if (!struct) {
1335
+ throw new Error(
1336
+ `Unknown structure id = ${structureId}, offset = ${this.offset - 1}`
1337
+ );
918
1338
  }
919
- this.offset += bytes;
920
- return this;
1339
+ return struct.extension.decode.call(this);
921
1340
  }
922
- writeChecksum(withConstructor = true) {
923
- const bytes = this.target.slice(this._checksumOffset, this.offset);
924
- let sum = 0;
925
- for (const val of bytes) {
926
- sum += val;
1341
+ /**
1342
+ * Reads a object.
1343
+ */
1344
+ readObject() {
1345
+ if (this._repeat) {
1346
+ if (this._repeat.pool > 0) {
1347
+ --this._repeat.pool;
1348
+ return this._repeat.value;
1349
+ } else {
1350
+ this._repeat = void 0;
1351
+ }
927
1352
  }
928
- if (withConstructor) {
929
- this.writeByte(CORE_TYPES.Checksum);
1353
+ const constructorId = this.readByte();
1354
+ const ext = this.extensions.get(constructorId);
1355
+ let value;
1356
+ if (ext) {
1357
+ value = ext.decode.call(this);
1358
+ } else {
1359
+ value = this._lastObject = this.readCore(constructorId);
930
1360
  }
931
- this.writeLength(sum);
932
- this._checksumOffset = this.offset;
933
- return this;
1361
+ return value;
934
1362
  }
935
- writeBytes(value) {
936
- const length = value.length;
937
- this.writeLength(length);
938
- this.allocate(length);
939
- this.target.set(value, this.offset);
940
- this.offset += length;
941
- return this;
1363
+ readObjectGzip() {
1364
+ const bytes = this.readGzip();
1365
+ const reader = new BinaryReader(bytes);
1366
+ reader.extensions = this.extensions;
1367
+ reader.dictionary = this.dictionary;
1368
+ reader.dictionaryExtended = this.dictionaryExtended;
1369
+ return reader.readObject();
942
1370
  }
943
- writeLength(value) {
944
- if (value < 254) {
945
- this.allocate(1);
946
- this.target[this.offset++] = value;
947
- } else {
948
- this.allocate(4);
949
- this.target[this.offset++] = 254;
950
- this.target[this.offset++] = value % 256;
951
- this.target[this.offset++] = (value >> 8) % 256;
952
- this.target[this.offset++] = (value >> 16) % 256;
1371
+ readGzip() {
1372
+ return pako.inflateRaw(this.readBytes());
1373
+ }
1374
+ readCore(constructorId) {
1375
+ switch (constructorId) {
1376
+ case CORE_TYPES.None:
1377
+ return this.readObject();
1378
+ case CORE_TYPES.GZIP:
1379
+ return this.readObjectGzip();
1380
+ case CORE_TYPES.BoolTrue:
1381
+ return true;
1382
+ case CORE_TYPES.BoolFalse:
1383
+ return false;
1384
+ case CORE_TYPES.Vector:
1385
+ return this.readVector(false);
1386
+ case CORE_TYPES.VectorDynamic:
1387
+ return this.readVectorDynamic(false);
1388
+ case CORE_TYPES.Null:
1389
+ return null;
1390
+ case CORE_TYPES.Binary:
1391
+ return this.readBytes();
1392
+ case CORE_TYPES.String:
1393
+ return this.readString();
1394
+ case CORE_TYPES.Date:
1395
+ return this.readDate();
1396
+ case CORE_TYPES.Int32:
1397
+ return this.readInt32();
1398
+ case CORE_TYPES.Int16:
1399
+ return this.readInt16();
1400
+ case CORE_TYPES.Int8:
1401
+ return this.readInt8();
1402
+ case CORE_TYPES.UInt32:
1403
+ return this.readInt32(false);
1404
+ case CORE_TYPES.UInt16:
1405
+ return this.readInt16(false);
1406
+ case CORE_TYPES.UInt8:
1407
+ return this.readInt8(false);
1408
+ case CORE_TYPES.Float:
1409
+ return this.readFloat();
1410
+ case CORE_TYPES.Double:
1411
+ return this.readDouble();
1412
+ case CORE_TYPES.Map:
1413
+ return this.readMap(false);
1414
+ case CORE_TYPES.Checksum:
1415
+ return void this.readChecksum(false);
1416
+ case CORE_TYPES.Structure:
1417
+ return this.readStructure(false);
1418
+ case CORE_TYPES.DictIndex: {
1419
+ const idx = this.readLength();
1420
+ return this.getDictionaryValue(idx);
1421
+ }
1422
+ case CORE_TYPES.DictValue: {
1423
+ const value = this.readString();
1424
+ this.dictionaryExtended.maybeInsert(value);
1425
+ return value;
1426
+ }
1427
+ case CORE_TYPES.Repeat: {
1428
+ const size = this.readLength();
1429
+ this._repeat = { pool: size - 1, value: this._lastObject };
1430
+ return this._lastObject;
1431
+ }
953
1432
  }
954
- return this;
1433
+ throw new Error(
1434
+ `Invalid constructor = ${CORE_TYPES[constructorId] || constructorId}, offset = ${this.offset - 1}`
1435
+ );
955
1436
  }
956
- writeVector(value) {
957
- const length = value.length;
958
- this.writeLength(length);
959
- for (let i = 0; i < length; i++) {
960
- if (value[i] === void 0) {
961
- this.writeNull();
962
- } else {
963
- this.writeObject(value[i]);
1437
+ getDictionaryValue(index) {
1438
+ let value = null;
1439
+ if (this.dictionary) {
1440
+ value = this.dictionary.getValue(index);
1441
+ }
1442
+ if (value === null) {
1443
+ value = this.dictionaryExtended.getValue(index);
1444
+ }
1445
+ return value;
1446
+ }
1447
+ readDictionary() {
1448
+ const constructorId = this.readByte();
1449
+ let key = null;
1450
+ switch (constructorId) {
1451
+ case CORE_TYPES.DictIndex: {
1452
+ const idx = this.readLength();
1453
+ key = this.getDictionaryValue(idx);
1454
+ break;
1455
+ }
1456
+ case CORE_TYPES.DictValue: {
1457
+ key = this.readString();
1458
+ this.dictionaryExtended.maybeInsert(key);
1459
+ break;
1460
+ }
1461
+ case CORE_TYPES.None: {
1462
+ key = null;
1463
+ break;
1464
+ }
1465
+ default: {
1466
+ this.seek(-1);
964
1467
  }
965
1468
  }
966
- return this;
967
- }
968
- writeMap(object) {
969
- for (const key in object) {
970
- if (object[key] === void 0) continue;
971
- this._last = noop;
972
- this.wireDictionary(key);
973
- this.writeObject(object[key]);
974
- }
975
- this.writeByte(CORE_TYPES.None);
976
- return this;
1469
+ return key;
977
1470
  }
978
- wireDictionary(value) {
979
- let idx = null;
980
- if (this.dictionary) {
981
- idx = this.dictionary.getIndex(value);
982
- }
983
- if (idx === null) {
984
- idx = this.dictionaryExtended.getIndex(value);
1471
+ readMap(checkConstructor = true) {
1472
+ if (checkConstructor) {
1473
+ this.assertConstructor(CORE_TYPES.Map);
985
1474
  }
986
- if (idx === null) {
987
- this.dictionaryExtended.maybeInsert(value);
988
- this.writeCore(CORE_TYPES.DictValue, value);
989
- } else {
990
- this.writeCore(CORE_TYPES.DictIndex, idx);
1475
+ const temp = {};
1476
+ let key = this.readDictionary();
1477
+ while (key !== null) {
1478
+ temp[key] = this.readObject();
1479
+ key = this.readDictionary();
991
1480
  }
992
- return this;
993
- }
994
- writeGzip(value) {
995
- const compressed = pako.deflateRaw(value, { level: 9 });
996
- this.writeBytes(compressed);
997
- return this;
1481
+ return temp;
998
1482
  }
999
- encode(value) {
1483
+ decode(value) {
1484
+ this.target = value;
1485
+ this._last = void 0;
1486
+ this._lastObject = void 0;
1487
+ this._repeat = void 0;
1000
1488
  this.offset = 0;
1001
1489
  this._checksumOffset = 0;
1002
- this._last = noop;
1003
- this._repeat = void 0;
1004
- this.target = byteArrayAllocate(256);
1005
- this.writeObject(value);
1006
- return this.getBuffer();
1007
- }
1008
- startDynamicVector() {
1009
- this.writeByte(CORE_TYPES.VectorDynamic);
1010
- return this;
1490
+ this.length = value.length;
1491
+ return this.readObject();
1011
1492
  }
1012
- endDynamicVector() {
1013
- this.writeByte(CORE_TYPES.None);
1014
- return this;
1493
+ /**
1494
+ * Reads a vector (a list) of objects.
1495
+ */
1496
+ readVector(checkConstructor = true) {
1497
+ if (checkConstructor) {
1498
+ this.assertConstructor(CORE_TYPES.Vector);
1499
+ }
1500
+ const count = this.readLength();
1501
+ const temp = [];
1502
+ for (let i = 0; i < count; i++) {
1503
+ temp.push(this.readObject());
1504
+ }
1505
+ return temp;
1015
1506
  }
1016
- _writeCustom(value) {
1017
- const start = this.offset;
1018
- this.allocate(1);
1019
- this.offset++;
1020
- let edgeExt;
1021
- for (const ext of this.extensions.values()) {
1022
- if (ext.token === -1) {
1023
- edgeExt = ext;
1024
- continue;
1507
+ /**
1508
+ * Reads a vector (a list) of objects.
1509
+ */
1510
+ readVectorDynamic(checkConstructor = true) {
1511
+ if (checkConstructor) {
1512
+ this.assertConstructor(CORE_TYPES.VectorDynamic);
1513
+ }
1514
+ const temp = [];
1515
+ let complete = false;
1516
+ while (this.length > this.offset) {
1517
+ const constructorId = this.readByte();
1518
+ if (constructorId === CORE_TYPES.None) {
1519
+ complete = true;
1520
+ break;
1025
1521
  }
1026
- ext.encode.call(this, value);
1027
- const processed = start + 1 < this.offset;
1028
- if (processed) {
1029
- const end = this.offset;
1030
- this.offset = start;
1031
- this.writeByte(ext.token);
1032
- this.offset = end;
1033
- return true;
1522
+ const ext = this.extensions.get(constructorId);
1523
+ let value;
1524
+ if (ext) {
1525
+ value = ext.decode.call(this);
1526
+ } else {
1527
+ value = this.readCore(constructorId);
1034
1528
  }
1529
+ temp.push(value);
1035
1530
  }
1036
- this.offset = start;
1037
- if (edgeExt) {
1038
- edgeExt.encode.call(this, value);
1039
- return start < this.offset;
1531
+ if (!complete) {
1532
+ const err = new Error(`DynamicVector incomplete.`);
1533
+ err.incomplete = true;
1534
+ Error.captureStackTrace(err, this.readDictionary);
1535
+ throw err;
1040
1536
  }
1041
- return false;
1537
+ this._last = temp;
1538
+ return temp;
1042
1539
  }
1043
- writeObject(value) {
1044
- if (value === void 0) return this;
1045
- const constructorId = coreType(value);
1046
- if (constructorId === CORE_TYPES.None) {
1047
- if (this._writeCustom(value)) {
1048
- return this;
1049
- }
1050
- throw new TypeError(`Invalid core type of ${value}`);
1540
+ readChecksum(checkConstructor = true) {
1541
+ const offset = this.offset;
1542
+ if (checkConstructor) {
1543
+ this.assertConstructor(CORE_TYPES.Checksum);
1051
1544
  }
1052
- if (this._last === value) {
1053
- this.writeRepeat();
1054
- } else {
1055
- this._last = value;
1056
- this._repeat = void 0;
1057
- this.writeCore(constructorId, value);
1545
+ const bytes = this.target.slice(this._checksumOffset, offset);
1546
+ const checksum = this.readInt32();
1547
+ let sum = 0;
1548
+ for (const val of bytes) {
1549
+ sum += val;
1058
1550
  }
1059
- return this;
1551
+ if (checksum - sum !== 0) {
1552
+ throw new Error(
1553
+ `Invalid checksum = ${checksum - sum}, offset = ${offset}`
1554
+ );
1555
+ }
1556
+ this._checksumOffset = this.offset;
1060
1557
  }
1061
- writeObjectGzip(value) {
1062
- const writer = new BinaryWriter();
1063
- writer.extensions = this.extensions;
1064
- writer.dictionary = this.dictionary;
1065
- writer.dictionaryExtended = this.dictionaryExtended;
1066
- writer.writeObject(value);
1067
- this.writeCore(CORE_TYPES.GZIP, writer.getBuffer());
1068
- return this;
1558
+ /**
1559
+ * Tells the current position on the stream.
1560
+ */
1561
+ tellPosition() {
1562
+ return this.offset;
1069
1563
  }
1070
- writeCore(constructorId, value) {
1071
- if (this.withGzip && SUPPORT_COMPRESSION.has(constructorId)) {
1072
- this.writeObjectGzip(value);
1073
- return this;
1074
- } else if (!NO_CONSTRUCTOR.has(constructorId)) {
1075
- this.writeByte(constructorId);
1076
- }
1077
- switch (constructorId) {
1078
- case CORE_TYPES.GZIP: {
1079
- return this.writeGzip(value);
1080
- }
1081
- case CORE_TYPES.DictIndex: {
1082
- return this.writeLength(value);
1083
- }
1084
- case CORE_TYPES.DictValue: {
1085
- return this.writeString(value);
1086
- }
1087
- case CORE_TYPES.BoolFalse: {
1088
- return this.writeBool(value);
1089
- }
1090
- case CORE_TYPES.BoolTrue: {
1091
- return this.writeBool(value);
1092
- }
1093
- case CORE_TYPES.Date: {
1094
- return this.writeDate(value);
1095
- }
1096
- case CORE_TYPES.Int32: {
1097
- return this.writeInt32(value);
1098
- }
1099
- case CORE_TYPES.Int16: {
1100
- return this.writeInt16(value);
1101
- }
1102
- case CORE_TYPES.Int8: {
1103
- return this.writeInt8(value);
1104
- }
1105
- case CORE_TYPES.UInt32: {
1106
- return this.writeInt32(value, false);
1107
- }
1108
- case CORE_TYPES.UInt16: {
1109
- return this.writeInt16(value, false);
1110
- }
1111
- case CORE_TYPES.UInt8: {
1112
- return this.writeInt8(value, false);
1113
- }
1114
- case CORE_TYPES.Double: {
1115
- return this.writeDouble(value);
1116
- }
1117
- case CORE_TYPES.Float: {
1118
- return this.writeFloat(value);
1119
- }
1120
- case CORE_TYPES.Null: {
1121
- return this.writeNull();
1122
- }
1123
- case CORE_TYPES.String: {
1124
- if (value.length <= 16) {
1125
- this.offset--;
1126
- return this.wireDictionary(value);
1127
- }
1128
- return this.writeString(value);
1129
- }
1130
- case CORE_TYPES.Vector: {
1131
- return this.writeVector(value);
1132
- }
1133
- case CORE_TYPES.Map: {
1134
- return this.writeMap(value);
1135
- }
1136
- }
1137
- return this;
1564
+ /**
1565
+ * Sets the current position on the stream.
1566
+ */
1567
+ setPosition(position) {
1568
+ this.offset = position;
1138
1569
  }
1139
- writeRepeat() {
1140
- if (!this._repeat) {
1141
- this.writeByte(CORE_TYPES.Repeat);
1142
- this._repeat = { count: 0, offset: this.offset };
1143
- }
1144
- this.offset = this._repeat.offset;
1145
- this._repeat.count++;
1146
- this.writeLength(this._repeat.count);
1147
- return this;
1570
+ /**
1571
+ * Seeks the stream position given an offset from the current position.
1572
+ * The offset may be negative.
1573
+ */
1574
+ seek(offset) {
1575
+ this.offset += offset;
1148
1576
  }
1149
1577
  }
1150
1578
 
1151
- export { BinaryWriter as B, CORE_TYPES as C, MAX_BUFFER_SIZE as M, BinaryReader as a, createDictionary as c };
1152
- //# sourceMappingURL=tl-pack.CkwM-fIb.mjs.map
1579
+ export { BinaryWriter as B, CORE_TYPES as C, MAX_BUFFER_SIZE as M, Structure as S, BinaryReader as a, createDictionary as c, defineStructure as d };
1580
+ //# sourceMappingURL=tl-pack.CxheH0R_.mjs.map