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