msgpackr 1.9.9 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/test.js CHANGED
@@ -910,7 +910,7 @@
910
910
  return readFixedString(length)
911
911
  } else { // not cacheable, go back and do a standard read
912
912
  position$1--;
913
- return read().toString()
913
+ return asSafeString(read())
914
914
  }
915
915
  let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position$1) : length > 0 ? src[position$1] : 0)) & 0xfff;
916
916
  let entry = keyCache[key];
@@ -962,9 +962,15 @@
962
962
  return entry.string = readFixedString(length)
963
963
  }
964
964
 
965
+ function asSafeString(property) {
966
+ if (typeof property === 'string') return property;
967
+ if (typeof property === 'number') return property.toString();
968
+ throw new Error('Invalid property type for record', typeof property);
969
+ }
965
970
  // the registration of the record definition extension (as "r")
966
971
  const recordDefinition = (id, highByte) => {
967
- let structure = read().map(property => property.toString()); // ensure that all keys are strings and that the array is mutable
972
+ let structure = read().map(asSafeString); // ensure that all keys are strings and
973
+ // that the array is mutable
968
974
  let firstByte = id;
969
975
  if (highByte !== undefined) {
970
976
  id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id);
@@ -984,6 +990,17 @@
984
990
  currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here
985
991
  currentExtensions[0].noBuffer = true;
986
992
 
993
+ currentExtensions[0x42] = (data) => {
994
+ // decode bigint
995
+ let length = data.length;
996
+ let value = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
997
+ for (let i = 1; i < length; i++) {
998
+ value <<= 8n;
999
+ value += BigInt(data[i]);
1000
+ }
1001
+ return value;
1002
+ };
1003
+
987
1004
  let errors = { Error, TypeError, ReferenceError };
988
1005
  currentExtensions[0x65] = () => {
989
1006
  let data = read();
@@ -992,6 +1009,7 @@
992
1009
 
993
1010
  currentExtensions[0x69] = (data) => {
994
1011
  // id extension (for structured clones)
1012
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
995
1013
  let id = dataView.getUint32(position$1 - 4);
996
1014
  if (!referenceMap)
997
1015
  referenceMap = new Map();
@@ -1015,6 +1033,7 @@
1015
1033
 
1016
1034
  currentExtensions[0x70] = (data) => {
1017
1035
  // pointer extension (for structured clones)
1036
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
1018
1037
  let id = dataView.getUint32(position$1 - 4);
1019
1038
  let refEntry = referenceMap.get(id);
1020
1039
  refEntry.used = true;
@@ -1268,6 +1287,7 @@
1268
1287
  }
1269
1288
  if (hasSharedUpdate)
1270
1289
  hasSharedUpdate = false;
1290
+ let encodingError;
1271
1291
  try {
1272
1292
  if (packr.randomAccessStructure && value && value.constructor && value.constructor === Object)
1273
1293
  writeStruct(value);
@@ -1318,6 +1338,9 @@
1318
1338
  return target
1319
1339
  }
1320
1340
  return target.subarray(start, position) // position can change if we call pack again in saveStructures, so we get the buffer now
1341
+ } catch(error) {
1342
+ encodingError = error;
1343
+ throw error;
1321
1344
  } finally {
1322
1345
  if (structures) {
1323
1346
  resetStructures();
@@ -1326,12 +1349,14 @@
1326
1349
  // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
1327
1350
  let returnBuffer = target.subarray(start, position);
1328
1351
  let newSharedData = prepareStructures$1(structures, packr);
1329
- if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
1330
- // get updated structures and try again if the update failed
1331
- return packr.pack(value, encodeOptions)
1352
+ if (!encodingError) { // TODO: If there is an encoding error, should make the structures as uninitialized so they get rebuilt next time
1353
+ if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
1354
+ // get updated structures and try again if the update failed
1355
+ return packr.pack(value, encodeOptions)
1356
+ }
1357
+ packr.lastNamedStructuresLength = sharedLength;
1358
+ return returnBuffer
1332
1359
  }
1333
- packr.lastNamedStructuresLength = sharedLength;
1334
- return returnBuffer
1335
1360
  }
1336
1361
  }
1337
1362
  if (encodeOptions & RESET_BUFFER_MODE)
@@ -1673,8 +1698,26 @@
1673
1698
  if (this.largeBigIntToFloat) {
1674
1699
  target[position++] = 0xcb;
1675
1700
  targetView.setFloat64(position, Number(value));
1701
+ } else if (this.useBigIntExtension && value < 2n**(1023n) && value > -(2n**(1023n))) {
1702
+ target[position++] = 0xc7;
1703
+ position++;
1704
+ target[position++] = 0x42; // "B" for BigInt
1705
+ let bytes = [];
1706
+ let alignedSign;
1707
+ do {
1708
+ let byte = value & 0xffn;
1709
+ alignedSign = (byte & 0x80n) === (value < 0n ? 0x80n : 0n);
1710
+ bytes.push(byte);
1711
+ value >>= 8n;
1712
+ } while (!((value === 0n || value === -1n) && alignedSign));
1713
+ target[position-2] = bytes.length;
1714
+ for (let i = bytes.length; i > 0;) {
1715
+ target[position++] = Number(bytes[--i]);
1716
+ }
1717
+ return
1676
1718
  } else {
1677
- throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, set largeBigIntToFloat to convert to float-64')
1719
+ throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, use' +
1720
+ ' useBigIntExtension or set largeBigIntToFloat to convert to float-64')
1678
1721
  }
1679
1722
  }
1680
1723
  position += 8;
@@ -2427,6 +2470,8 @@
2427
2470
  position = updatedPosition;
2428
2471
  } else queuedReferences.push(key, value, keyIndex);
2429
2472
  break;
2473
+ default:
2474
+ queuedReferences.push(key, value, keyIndex);
2430
2475
  }
2431
2476
  keyIndex++;
2432
2477
  }
@@ -3341,6 +3386,22 @@
3341
3386
  assert.equal(pack(123).length, 1);
3342
3387
  });
3343
3388
 
3389
+ test('BigInt', function() {
3390
+ let packr = new Packr({useBigIntExtension: true});
3391
+ let data = {
3392
+ a: 3333333333333333333333333333n,
3393
+ b: 1234567890123456789012345678901234567890n,
3394
+ c: -3333333333333333333333333333n,
3395
+ d: -352523523642364364364264264264264264262642642n,
3396
+ e: 0xffffffffffffffffffffffffffn,
3397
+ f: -0xffffffffffffffffffffffffffn,
3398
+ };
3399
+ let serialized = packr.pack(data);
3400
+ let deserialized = packr.unpack(serialized);
3401
+ assert.deepEqual(data, deserialized);
3402
+ });
3403
+
3404
+
3344
3405
  test('extended class pack/unpack', function(){
3345
3406
  function Extended() {
3346
3407
 
@@ -3610,6 +3671,19 @@
3610
3671
  var deserialized = unpack(serialized);
3611
3672
  assert.equal(deserialized.aDate, data.aDate.toString());
3612
3673
  });
3674
+ test('standard pack fails on circular reference with shared structures', function () {
3675
+ var data = {};
3676
+ data.self = data;
3677
+ let structures = [];
3678
+ let packr = new Packr({
3679
+ structures,
3680
+ saveStructures(structures) {
3681
+ }
3682
+ });
3683
+ assert.throws(function () {
3684
+ packr.pack(data);
3685
+ });
3686
+ });
3613
3687
 
3614
3688
  test('proto handling', function() {
3615
3689
  var objectWithProto = JSON.parse('{"__proto__":{"foo":3}}');