bson 6.3.0 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -127,6 +127,15 @@ class BSONRuntimeError extends BSONError {
127
127
  super(message);
128
128
  }
129
129
  }
130
+ class BSONOffsetError extends BSONError {
131
+ get name() {
132
+ return 'BSONOffsetError';
133
+ }
134
+ constructor(message, offset) {
135
+ super(`${message}. offset: ${offset}`);
136
+ this.offset = offset;
137
+ }
138
+ }
130
139
 
131
140
  const FIRST_BIT = 0x80;
132
141
  const FIRST_TWO_BITS = 0xc0;
@@ -165,7 +174,7 @@ function validateUtf8(bytes, start, end) {
165
174
  return !continuation;
166
175
  }
167
176
 
168
- function tryLatin(uint8array, start, end) {
177
+ function tryReadBasicLatin(uint8array, start, end) {
169
178
  if (uint8array.length === 0) {
170
179
  return '';
171
180
  }
@@ -200,6 +209,21 @@ function tryLatin(uint8array, start, end) {
200
209
  }
201
210
  return String.fromCharCode(...latinBytes);
202
211
  }
212
+ function tryWriteBasicLatin(destination, source, offset) {
213
+ if (source.length === 0)
214
+ return 0;
215
+ if (source.length > 25)
216
+ return null;
217
+ if (destination.length - offset < source.length)
218
+ return null;
219
+ for (let charOffset = 0, destinationOffset = offset; charOffset < source.length; charOffset++, destinationOffset++) {
220
+ const char = source.charCodeAt(charOffset);
221
+ if (char > 127)
222
+ return null;
223
+ destination[destinationOffset] = char;
224
+ }
225
+ return source.length;
226
+ }
203
227
 
204
228
  function nodejsMathRandomBytes(byteLength) {
205
229
  return nodeJsByteUtils.fromNumberArray(Array.from({ length: byteLength }, () => Math.floor(Math.random() * 256)));
@@ -232,6 +256,9 @@ const nodeJsByteUtils = {
232
256
  allocate(size) {
233
257
  return Buffer.alloc(size);
234
258
  },
259
+ allocateUnsafe(size) {
260
+ return Buffer.allocUnsafe(size);
261
+ },
235
262
  equals(a, b) {
236
263
  return nodeJsByteUtils.toLocalBufferType(a).equals(b);
237
264
  },
@@ -256,11 +283,8 @@ const nodeJsByteUtils = {
256
283
  toHex(buffer) {
257
284
  return nodeJsByteUtils.toLocalBufferType(buffer).toString('hex');
258
285
  },
259
- fromUTF8(text) {
260
- return Buffer.from(text, 'utf8');
261
- },
262
286
  toUTF8(buffer, start, end, fatal) {
263
- const basicLatin = end - start <= 20 ? tryLatin(buffer, start, end) : null;
287
+ const basicLatin = end - start <= 20 ? tryReadBasicLatin(buffer, start, end) : null;
264
288
  if (basicLatin != null) {
265
289
  return basicLatin;
266
290
  }
@@ -281,6 +305,10 @@ const nodeJsByteUtils = {
281
305
  return Buffer.byteLength(input, 'utf8');
282
306
  },
283
307
  encodeUTF8Into(buffer, source, byteOffset) {
308
+ const latinBytesWritten = tryWriteBasicLatin(buffer, source, byteOffset);
309
+ if (latinBytesWritten != null) {
310
+ return latinBytesWritten;
311
+ }
284
312
  return nodeJsByteUtils.toLocalBufferType(buffer).write(source, byteOffset, undefined, 'utf8');
285
313
  },
286
314
  randomBytes: nodejsRandomBytes
@@ -336,6 +364,9 @@ const webByteUtils = {
336
364
  }
337
365
  return new Uint8Array(size);
338
366
  },
367
+ allocateUnsafe(size) {
368
+ return webByteUtils.allocate(size);
369
+ },
339
370
  equals(a, b) {
340
371
  if (a.byteLength !== b.byteLength) {
341
372
  return false;
@@ -382,11 +413,8 @@ const webByteUtils = {
382
413
  toHex(uint8array) {
383
414
  return Array.from(uint8array, byte => byte.toString(16).padStart(2, '0')).join('');
384
415
  },
385
- fromUTF8(text) {
386
- return new TextEncoder().encode(text);
387
- },
388
416
  toUTF8(uint8array, start, end, fatal) {
389
- const basicLatin = end - start <= 20 ? tryLatin(uint8array, start, end) : null;
417
+ const basicLatin = end - start <= 20 ? tryReadBasicLatin(uint8array, start, end) : null;
390
418
  if (basicLatin != null) {
391
419
  return basicLatin;
392
420
  }
@@ -401,11 +429,11 @@ const webByteUtils = {
401
429
  return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
402
430
  },
403
431
  utf8ByteLength(input) {
404
- return webByteUtils.fromUTF8(input).byteLength;
432
+ return new TextEncoder().encode(input).byteLength;
405
433
  },
406
- encodeUTF8Into(buffer, source, byteOffset) {
407
- const bytes = webByteUtils.fromUTF8(source);
408
- buffer.set(bytes, byteOffset);
434
+ encodeUTF8Into(uint8array, source, byteOffset) {
435
+ const bytes = new TextEncoder().encode(source);
436
+ uint8array.set(bytes, byteOffset);
409
437
  return bytes.byteLength;
410
438
  },
411
439
  randomBytes: webRandomBytes
@@ -413,11 +441,6 @@ const webByteUtils = {
413
441
 
414
442
  const hasGlobalBuffer = typeof Buffer === 'function' && Buffer.prototype?._isBuffer !== true;
415
443
  const ByteUtils = hasGlobalBuffer ? nodeJsByteUtils : webByteUtils;
416
- class BSONDataView extends DataView {
417
- static fromUint8Array(input) {
418
- return new DataView(input.buffer, input.byteOffset, input.byteLength);
419
- }
420
- }
421
444
 
422
445
  class BSONValue {
423
446
  get [Symbol.for('@@mdb.bson.version')]() {
@@ -594,6 +617,7 @@ Binary.SUBTYPE_UUID = 4;
594
617
  Binary.SUBTYPE_MD5 = 5;
595
618
  Binary.SUBTYPE_ENCRYPTED = 6;
596
619
  Binary.SUBTYPE_COLUMN = 7;
620
+ Binary.SUBTYPE_SENSITIVE = 8;
597
621
  Binary.SUBTYPE_USER_DEFINED = 128;
598
622
  const UUID_BYTE_LENGTH = 16;
599
623
  const UUID_WITHOUT_DASHES = /^[0-9A-F]{32}$/i;
@@ -1837,7 +1861,7 @@ class Decimal128 extends BSONValue {
1837
1861
  if (isNegative) {
1838
1862
  dec.high = dec.high.or(Long.fromString('9223372036854775808'));
1839
1863
  }
1840
- const buffer = ByteUtils.allocate(16);
1864
+ const buffer = ByteUtils.allocateUnsafe(16);
1841
1865
  index = 0;
1842
1866
  buffer[index++] = dec.low.low & 0xff;
1843
1867
  buffer[index++] = (dec.low.low >> 8) & 0xff;
@@ -2110,9 +2134,126 @@ class MinKey extends BSONValue {
2110
2134
  }
2111
2135
  }
2112
2136
 
2137
+ const FLOAT = new Float64Array(1);
2138
+ const FLOAT_BYTES = new Uint8Array(FLOAT.buffer, 0, 8);
2139
+ FLOAT[0] = -1;
2140
+ const isBigEndian = FLOAT_BYTES[7] === 0;
2141
+ const NumberUtils = {
2142
+ getInt32LE(source, offset) {
2143
+ return (source[offset] |
2144
+ (source[offset + 1] << 8) |
2145
+ (source[offset + 2] << 16) |
2146
+ (source[offset + 3] << 24));
2147
+ },
2148
+ getUint32LE(source, offset) {
2149
+ return (source[offset] +
2150
+ source[offset + 1] * 256 +
2151
+ source[offset + 2] * 65536 +
2152
+ source[offset + 3] * 16777216);
2153
+ },
2154
+ getUint32BE(source, offset) {
2155
+ return (source[offset + 3] +
2156
+ source[offset + 2] * 256 +
2157
+ source[offset + 1] * 65536 +
2158
+ source[offset] * 16777216);
2159
+ },
2160
+ getBigInt64LE(source, offset) {
2161
+ const lo = NumberUtils.getUint32LE(source, offset);
2162
+ const hi = NumberUtils.getUint32LE(source, offset + 4);
2163
+ return (BigInt(hi) << BigInt(32)) + BigInt(lo);
2164
+ },
2165
+ getFloat64LE: isBigEndian
2166
+ ? (source, offset) => {
2167
+ FLOAT_BYTES[7] = source[offset];
2168
+ FLOAT_BYTES[6] = source[offset + 1];
2169
+ FLOAT_BYTES[5] = source[offset + 2];
2170
+ FLOAT_BYTES[4] = source[offset + 3];
2171
+ FLOAT_BYTES[3] = source[offset + 4];
2172
+ FLOAT_BYTES[2] = source[offset + 5];
2173
+ FLOAT_BYTES[1] = source[offset + 6];
2174
+ FLOAT_BYTES[0] = source[offset + 7];
2175
+ return FLOAT[0];
2176
+ }
2177
+ : (source, offset) => {
2178
+ FLOAT_BYTES[0] = source[offset];
2179
+ FLOAT_BYTES[1] = source[offset + 1];
2180
+ FLOAT_BYTES[2] = source[offset + 2];
2181
+ FLOAT_BYTES[3] = source[offset + 3];
2182
+ FLOAT_BYTES[4] = source[offset + 4];
2183
+ FLOAT_BYTES[5] = source[offset + 5];
2184
+ FLOAT_BYTES[6] = source[offset + 6];
2185
+ FLOAT_BYTES[7] = source[offset + 7];
2186
+ return FLOAT[0];
2187
+ },
2188
+ setInt32BE(destination, offset, value) {
2189
+ destination[offset + 3] = value;
2190
+ value >>>= 8;
2191
+ destination[offset + 2] = value;
2192
+ value >>>= 8;
2193
+ destination[offset + 1] = value;
2194
+ value >>>= 8;
2195
+ destination[offset] = value;
2196
+ return 4;
2197
+ },
2198
+ setInt32LE(destination, offset, value) {
2199
+ destination[offset] = value;
2200
+ value >>>= 8;
2201
+ destination[offset + 1] = value;
2202
+ value >>>= 8;
2203
+ destination[offset + 2] = value;
2204
+ value >>>= 8;
2205
+ destination[offset + 3] = value;
2206
+ return 4;
2207
+ },
2208
+ setBigInt64LE(destination, offset, value) {
2209
+ const mask32bits = BigInt(4294967295);
2210
+ let lo = Number(value & mask32bits);
2211
+ destination[offset] = lo;
2212
+ lo >>= 8;
2213
+ destination[offset + 1] = lo;
2214
+ lo >>= 8;
2215
+ destination[offset + 2] = lo;
2216
+ lo >>= 8;
2217
+ destination[offset + 3] = lo;
2218
+ let hi = Number((value >> BigInt(32)) & mask32bits);
2219
+ destination[offset + 4] = hi;
2220
+ hi >>= 8;
2221
+ destination[offset + 5] = hi;
2222
+ hi >>= 8;
2223
+ destination[offset + 6] = hi;
2224
+ hi >>= 8;
2225
+ destination[offset + 7] = hi;
2226
+ return 8;
2227
+ },
2228
+ setFloat64LE: isBigEndian
2229
+ ? (destination, offset, value) => {
2230
+ FLOAT[0] = value;
2231
+ destination[offset] = FLOAT_BYTES[7];
2232
+ destination[offset + 1] = FLOAT_BYTES[6];
2233
+ destination[offset + 2] = FLOAT_BYTES[5];
2234
+ destination[offset + 3] = FLOAT_BYTES[4];
2235
+ destination[offset + 4] = FLOAT_BYTES[3];
2236
+ destination[offset + 5] = FLOAT_BYTES[2];
2237
+ destination[offset + 6] = FLOAT_BYTES[1];
2238
+ destination[offset + 7] = FLOAT_BYTES[0];
2239
+ return 8;
2240
+ }
2241
+ : (destination, offset, value) => {
2242
+ FLOAT[0] = value;
2243
+ destination[offset] = FLOAT_BYTES[0];
2244
+ destination[offset + 1] = FLOAT_BYTES[1];
2245
+ destination[offset + 2] = FLOAT_BYTES[2];
2246
+ destination[offset + 3] = FLOAT_BYTES[3];
2247
+ destination[offset + 4] = FLOAT_BYTES[4];
2248
+ destination[offset + 5] = FLOAT_BYTES[5];
2249
+ destination[offset + 6] = FLOAT_BYTES[6];
2250
+ destination[offset + 7] = FLOAT_BYTES[7];
2251
+ return 8;
2252
+ }
2253
+ };
2254
+
2113
2255
  const checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$');
2114
2256
  let PROCESS_UNIQUE = null;
2115
- const kId = Symbol('id');
2116
2257
  class ObjectId extends BSONValue {
2117
2258
  get _bsontype() {
2118
2259
  return 'ObjectId';
@@ -2135,14 +2276,14 @@ class ObjectId extends BSONValue {
2135
2276
  workingId = inputId;
2136
2277
  }
2137
2278
  if (workingId == null || typeof workingId === 'number') {
2138
- this[kId] = ObjectId.generate(typeof workingId === 'number' ? workingId : undefined);
2279
+ this.buffer = ObjectId.generate(typeof workingId === 'number' ? workingId : undefined);
2139
2280
  }
2140
2281
  else if (ArrayBuffer.isView(workingId) && workingId.byteLength === 12) {
2141
- this[kId] = ByteUtils.toLocalBufferType(workingId);
2282
+ this.buffer = ByteUtils.toLocalBufferType(workingId);
2142
2283
  }
2143
2284
  else if (typeof workingId === 'string') {
2144
2285
  if (workingId.length === 24 && checkForHexRegExp.test(workingId)) {
2145
- this[kId] = ByteUtils.fromHex(workingId);
2286
+ this.buffer = ByteUtils.fromHex(workingId);
2146
2287
  }
2147
2288
  else {
2148
2289
  throw new BSONError('input must be a 24 character hex string, 12 byte Uint8Array, or an integer');
@@ -2156,10 +2297,10 @@ class ObjectId extends BSONValue {
2156
2297
  }
2157
2298
  }
2158
2299
  get id() {
2159
- return this[kId];
2300
+ return this.buffer;
2160
2301
  }
2161
2302
  set id(value) {
2162
- this[kId] = value;
2303
+ this.buffer = value;
2163
2304
  if (ObjectId.cacheHexString) {
2164
2305
  this.__id = ByteUtils.toHex(value);
2165
2306
  }
@@ -2182,8 +2323,8 @@ class ObjectId extends BSONValue {
2182
2323
  time = Math.floor(Date.now() / 1000);
2183
2324
  }
2184
2325
  const inc = ObjectId.getInc();
2185
- const buffer = ByteUtils.allocate(12);
2186
- BSONDataView.fromUint8Array(buffer).setUint32(0, time, false);
2326
+ const buffer = ByteUtils.allocateUnsafe(12);
2327
+ NumberUtils.setInt32BE(buffer, 0, time);
2187
2328
  if (PROCESS_UNIQUE === null) {
2188
2329
  PROCESS_UNIQUE = ByteUtils.randomBytes(5);
2189
2330
  }
@@ -2218,7 +2359,7 @@ class ObjectId extends BSONValue {
2218
2359
  return false;
2219
2360
  }
2220
2361
  if (ObjectId.is(otherId)) {
2221
- return this[kId][11] === otherId[kId][11] && ByteUtils.equals(this[kId], otherId[kId]);
2362
+ return (this.buffer[11] === otherId.buffer[11] && ByteUtils.equals(this.buffer, otherId.buffer));
2222
2363
  }
2223
2364
  if (typeof otherId === 'string') {
2224
2365
  return otherId.toLowerCase() === this.toHexString();
@@ -2232,16 +2373,33 @@ class ObjectId extends BSONValue {
2232
2373
  }
2233
2374
  getTimestamp() {
2234
2375
  const timestamp = new Date();
2235
- const time = BSONDataView.fromUint8Array(this.id).getUint32(0, false);
2376
+ const time = NumberUtils.getUint32BE(this.buffer, 0);
2236
2377
  timestamp.setTime(Math.floor(time) * 1000);
2237
2378
  return timestamp;
2238
2379
  }
2239
2380
  static createPk() {
2240
2381
  return new ObjectId();
2241
2382
  }
2383
+ serializeInto(uint8array, index) {
2384
+ uint8array[index] = this.buffer[0];
2385
+ uint8array[index + 1] = this.buffer[1];
2386
+ uint8array[index + 2] = this.buffer[2];
2387
+ uint8array[index + 3] = this.buffer[3];
2388
+ uint8array[index + 4] = this.buffer[4];
2389
+ uint8array[index + 5] = this.buffer[5];
2390
+ uint8array[index + 6] = this.buffer[6];
2391
+ uint8array[index + 7] = this.buffer[7];
2392
+ uint8array[index + 8] = this.buffer[8];
2393
+ uint8array[index + 9] = this.buffer[9];
2394
+ uint8array[index + 10] = this.buffer[10];
2395
+ uint8array[index + 11] = this.buffer[11];
2396
+ return 12;
2397
+ }
2242
2398
  static createFromTime(time) {
2243
- const buffer = ByteUtils.fromNumberArray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
2244
- BSONDataView.fromUint8Array(buffer).setUint32(0, time, false);
2399
+ const buffer = ByteUtils.allocate(12);
2400
+ for (let i = 11; i >= 4; i--)
2401
+ buffer[i] = 0;
2402
+ NumberUtils.setInt32BE(buffer, 0, time);
2245
2403
  return new ObjectId(buffer);
2246
2404
  }
2247
2405
  static createFromHexString(hexString) {
@@ -2613,10 +2771,7 @@ const JS_INT_MIN_LONG = Long.fromNumber(JS_INT_MIN);
2613
2771
  function internalDeserialize(buffer, options, isArray) {
2614
2772
  options = options == null ? {} : options;
2615
2773
  const index = options && options.index ? options.index : 0;
2616
- const size = buffer[index] |
2617
- (buffer[index + 1] << 8) |
2618
- (buffer[index + 2] << 16) |
2619
- (buffer[index + 3] << 24);
2774
+ const size = NumberUtils.getInt32LE(buffer, index);
2620
2775
  if (size < 5) {
2621
2776
  throw new BSONError(`bson size must be >= 5, is ${size}`);
2622
2777
  }
@@ -2652,7 +2807,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2652
2807
  const validation = options.validation == null ? { utf8: true } : options.validation;
2653
2808
  let globalUTFValidation = true;
2654
2809
  let validationSetting;
2655
- const utf8KeysSet = new Set();
2810
+ let utf8KeysSet;
2656
2811
  const utf8ValidatedKeys = validation.utf8;
2657
2812
  if (typeof utf8ValidatedKeys === 'boolean') {
2658
2813
  validationSetting = utf8ValidatedKeys;
@@ -2674,6 +2829,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2674
2829
  }
2675
2830
  }
2676
2831
  if (!globalUTFValidation) {
2832
+ utf8KeysSet = new Set();
2677
2833
  for (const key of Object.keys(utf8ValidatedKeys)) {
2678
2834
  utf8KeysSet.add(key);
2679
2835
  }
@@ -2681,14 +2837,14 @@ function deserializeObject(buffer, index, options, isArray = false) {
2681
2837
  const startIndex = index;
2682
2838
  if (buffer.length < 5)
2683
2839
  throw new BSONError('corrupt bson message < 5 bytes long');
2684
- const size = buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
2840
+ const size = NumberUtils.getInt32LE(buffer, index);
2841
+ index += 4;
2685
2842
  if (size < 5 || size > buffer.length)
2686
2843
  throw new BSONError('corrupt bson message');
2687
2844
  const object = isArray ? [] : {};
2688
2845
  let arrayIndex = 0;
2689
2846
  const done = false;
2690
2847
  let isPossibleDBRef = isArray ? false : null;
2691
- const dataview = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
2692
2848
  while (!done) {
2693
2849
  const elementType = buffer[index++];
2694
2850
  if (elementType === 0)
@@ -2701,7 +2857,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2701
2857
  throw new BSONError('Bad BSON Document: illegal CString');
2702
2858
  const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i, false);
2703
2859
  let shouldValidateKey = true;
2704
- if (globalUTFValidation || utf8KeysSet.has(name)) {
2860
+ if (globalUTFValidation || utf8KeysSet?.has(name)) {
2705
2861
  shouldValidateKey = validationSetting;
2706
2862
  }
2707
2863
  else {
@@ -2713,10 +2869,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2713
2869
  let value;
2714
2870
  index = i + 1;
2715
2871
  if (elementType === BSON_DATA_STRING) {
2716
- const stringSize = buffer[index++] |
2717
- (buffer[index++] << 8) |
2718
- (buffer[index++] << 16) |
2719
- (buffer[index++] << 24);
2872
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
2873
+ index += 4;
2720
2874
  if (stringSize <= 0 ||
2721
2875
  stringSize > buffer.length - index ||
2722
2876
  buffer[index + stringSize - 1] !== 0) {
@@ -2726,38 +2880,30 @@ function deserializeObject(buffer, index, options, isArray = false) {
2726
2880
  index = index + stringSize;
2727
2881
  }
2728
2882
  else if (elementType === BSON_DATA_OID) {
2729
- const oid = ByteUtils.allocate(12);
2730
- oid.set(buffer.subarray(index, index + 12));
2883
+ const oid = ByteUtils.allocateUnsafe(12);
2884
+ for (let i = 0; i < 12; i++)
2885
+ oid[i] = buffer[index + i];
2731
2886
  value = new ObjectId(oid);
2732
2887
  index = index + 12;
2733
2888
  }
2734
2889
  else if (elementType === BSON_DATA_INT && promoteValues === false) {
2735
- value = new Int32(buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24));
2890
+ value = new Int32(NumberUtils.getInt32LE(buffer, index));
2891
+ index += 4;
2736
2892
  }
2737
2893
  else if (elementType === BSON_DATA_INT) {
2738
- value =
2739
- buffer[index++] |
2740
- (buffer[index++] << 8) |
2741
- (buffer[index++] << 16) |
2742
- (buffer[index++] << 24);
2743
- }
2744
- else if (elementType === BSON_DATA_NUMBER && promoteValues === false) {
2745
- value = new Double(dataview.getFloat64(index, true));
2746
- index = index + 8;
2894
+ value = NumberUtils.getInt32LE(buffer, index);
2895
+ index += 4;
2747
2896
  }
2748
2897
  else if (elementType === BSON_DATA_NUMBER) {
2749
- value = dataview.getFloat64(index, true);
2750
- index = index + 8;
2898
+ value = NumberUtils.getFloat64LE(buffer, index);
2899
+ index += 8;
2900
+ if (promoteValues === false)
2901
+ value = new Double(value);
2751
2902
  }
2752
2903
  else if (elementType === BSON_DATA_DATE) {
2753
- const lowBits = buffer[index++] |
2754
- (buffer[index++] << 8) |
2755
- (buffer[index++] << 16) |
2756
- (buffer[index++] << 24);
2757
- const highBits = buffer[index++] |
2758
- (buffer[index++] << 8) |
2759
- (buffer[index++] << 16) |
2760
- (buffer[index++] << 24);
2904
+ const lowBits = NumberUtils.getInt32LE(buffer, index);
2905
+ const highBits = NumberUtils.getInt32LE(buffer, index + 4);
2906
+ index += 8;
2761
2907
  value = new Date(new Long(lowBits, highBits).toNumber());
2762
2908
  }
2763
2909
  else if (elementType === BSON_DATA_BOOLEAN) {
@@ -2767,10 +2913,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2767
2913
  }
2768
2914
  else if (elementType === BSON_DATA_OBJECT) {
2769
2915
  const _index = index;
2770
- const objectSize = buffer[index] |
2771
- (buffer[index + 1] << 8) |
2772
- (buffer[index + 2] << 16) |
2773
- (buffer[index + 3] << 24);
2916
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2774
2917
  if (objectSize <= 0 || objectSize > buffer.length - index)
2775
2918
  throw new BSONError('bad embedded document length in bson');
2776
2919
  if (raw) {
@@ -2787,10 +2930,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2787
2930
  }
2788
2931
  else if (elementType === BSON_DATA_ARRAY) {
2789
2932
  const _index = index;
2790
- const objectSize = buffer[index] |
2791
- (buffer[index + 1] << 8) |
2792
- (buffer[index + 2] << 16) |
2793
- (buffer[index + 3] << 24);
2933
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2794
2934
  let arrayOptions = options;
2795
2935
  const stopIndex = index + objectSize;
2796
2936
  if (fieldsAsRaw && fieldsAsRaw[name]) {
@@ -2813,40 +2953,36 @@ function deserializeObject(buffer, index, options, isArray = false) {
2813
2953
  value = null;
2814
2954
  }
2815
2955
  else if (elementType === BSON_DATA_LONG) {
2816
- const dataview = BSONDataView.fromUint8Array(buffer.subarray(index, index + 8));
2817
- const lowBits = buffer[index++] |
2818
- (buffer[index++] << 8) |
2819
- (buffer[index++] << 16) |
2820
- (buffer[index++] << 24);
2821
- const highBits = buffer[index++] |
2822
- (buffer[index++] << 8) |
2823
- (buffer[index++] << 16) |
2824
- (buffer[index++] << 24);
2825
- const long = new Long(lowBits, highBits);
2826
2956
  if (useBigInt64) {
2827
- value = dataview.getBigInt64(0, true);
2828
- }
2829
- else if (promoteLongs && promoteValues === true) {
2830
- value =
2831
- long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
2832
- ? long.toNumber()
2833
- : long;
2957
+ value = NumberUtils.getBigInt64LE(buffer, index);
2958
+ index += 8;
2834
2959
  }
2835
2960
  else {
2836
- value = long;
2961
+ const lowBits = NumberUtils.getInt32LE(buffer, index);
2962
+ const highBits = NumberUtils.getInt32LE(buffer, index + 4);
2963
+ index += 8;
2964
+ const long = new Long(lowBits, highBits);
2965
+ if (promoteLongs && promoteValues === true) {
2966
+ value =
2967
+ long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
2968
+ ? long.toNumber()
2969
+ : long;
2970
+ }
2971
+ else {
2972
+ value = long;
2973
+ }
2837
2974
  }
2838
2975
  }
2839
2976
  else if (elementType === BSON_DATA_DECIMAL128) {
2840
- const bytes = ByteUtils.allocate(16);
2841
- bytes.set(buffer.subarray(index, index + 16), 0);
2977
+ const bytes = ByteUtils.allocateUnsafe(16);
2978
+ for (let i = 0; i < 16; i++)
2979
+ bytes[i] = buffer[index + i];
2842
2980
  index = index + 16;
2843
2981
  value = new Decimal128(bytes);
2844
2982
  }
2845
2983
  else if (elementType === BSON_DATA_BINARY) {
2846
- let binarySize = buffer[index++] |
2847
- (buffer[index++] << 8) |
2848
- (buffer[index++] << 16) |
2849
- (buffer[index++] << 24);
2984
+ let binarySize = NumberUtils.getInt32LE(buffer, index);
2985
+ index += 4;
2850
2986
  const totalBinarySize = binarySize;
2851
2987
  const subType = buffer[index++];
2852
2988
  if (binarySize < 0)
@@ -2855,11 +2991,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2855
2991
  throw new BSONError('Binary type size larger than document size');
2856
2992
  if (buffer['slice'] != null) {
2857
2993
  if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
2858
- binarySize =
2859
- buffer[index++] |
2860
- (buffer[index++] << 8) |
2861
- (buffer[index++] << 16) |
2862
- (buffer[index++] << 24);
2994
+ binarySize = NumberUtils.getInt32LE(buffer, index);
2995
+ index += 4;
2863
2996
  if (binarySize < 0)
2864
2997
  throw new BSONError('Negative binary type element size found for subtype 0x02');
2865
2998
  if (binarySize > totalBinarySize - 4)
@@ -2878,13 +3011,9 @@ function deserializeObject(buffer, index, options, isArray = false) {
2878
3011
  }
2879
3012
  }
2880
3013
  else {
2881
- const _buffer = ByteUtils.allocate(binarySize);
2882
3014
  if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
2883
- binarySize =
2884
- buffer[index++] |
2885
- (buffer[index++] << 8) |
2886
- (buffer[index++] << 16) |
2887
- (buffer[index++] << 24);
3015
+ binarySize = NumberUtils.getInt32LE(buffer, index);
3016
+ index += 4;
2888
3017
  if (binarySize < 0)
2889
3018
  throw new BSONError('Negative binary type element size found for subtype 0x02');
2890
3019
  if (binarySize > totalBinarySize - 4)
@@ -2892,11 +3021,11 @@ function deserializeObject(buffer, index, options, isArray = false) {
2892
3021
  if (binarySize < totalBinarySize - 4)
2893
3022
  throw new BSONError('Binary type with subtype 0x02 contains too short binary size');
2894
3023
  }
2895
- for (i = 0; i < binarySize; i++) {
2896
- _buffer[i] = buffer[index + i];
2897
- }
2898
3024
  if (promoteBuffers && promoteValues) {
2899
- value = _buffer;
3025
+ value = ByteUtils.allocateUnsafe(binarySize);
3026
+ for (i = 0; i < binarySize; i++) {
3027
+ value[i] = buffer[index + i];
3028
+ }
2900
3029
  }
2901
3030
  else {
2902
3031
  value = new Binary(buffer.slice(index, index + binarySize), subType);
@@ -2960,10 +3089,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2960
3089
  value = new BSONRegExp(source, regExpOptions);
2961
3090
  }
2962
3091
  else if (elementType === BSON_DATA_SYMBOL) {
2963
- const stringSize = buffer[index++] |
2964
- (buffer[index++] << 8) |
2965
- (buffer[index++] << 16) |
2966
- (buffer[index++] << 24);
3092
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3093
+ index += 4;
2967
3094
  if (stringSize <= 0 ||
2968
3095
  stringSize > buffer.length - index ||
2969
3096
  buffer[index + stringSize - 1] !== 0) {
@@ -2974,15 +3101,11 @@ function deserializeObject(buffer, index, options, isArray = false) {
2974
3101
  index = index + stringSize;
2975
3102
  }
2976
3103
  else if (elementType === BSON_DATA_TIMESTAMP) {
2977
- const i = buffer[index++] +
2978
- buffer[index++] * (1 << 8) +
2979
- buffer[index++] * (1 << 16) +
2980
- buffer[index++] * (1 << 24);
2981
- const t = buffer[index++] +
2982
- buffer[index++] * (1 << 8) +
2983
- buffer[index++] * (1 << 16) +
2984
- buffer[index++] * (1 << 24);
2985
- value = new Timestamp({ i, t });
3104
+ value = new Timestamp({
3105
+ i: NumberUtils.getUint32LE(buffer, index),
3106
+ t: NumberUtils.getUint32LE(buffer, index + 4)
3107
+ });
3108
+ index += 8;
2986
3109
  }
2987
3110
  else if (elementType === BSON_DATA_MIN_KEY) {
2988
3111
  value = new MinKey();
@@ -2991,10 +3114,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2991
3114
  value = new MaxKey();
2992
3115
  }
2993
3116
  else if (elementType === BSON_DATA_CODE) {
2994
- const stringSize = buffer[index++] |
2995
- (buffer[index++] << 8) |
2996
- (buffer[index++] << 16) |
2997
- (buffer[index++] << 24);
3117
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3118
+ index += 4;
2998
3119
  if (stringSize <= 0 ||
2999
3120
  stringSize > buffer.length - index ||
3000
3121
  buffer[index + stringSize - 1] !== 0) {
@@ -3005,17 +3126,13 @@ function deserializeObject(buffer, index, options, isArray = false) {
3005
3126
  index = index + stringSize;
3006
3127
  }
3007
3128
  else if (elementType === BSON_DATA_CODE_W_SCOPE) {
3008
- const totalSize = buffer[index++] |
3009
- (buffer[index++] << 8) |
3010
- (buffer[index++] << 16) |
3011
- (buffer[index++] << 24);
3129
+ const totalSize = NumberUtils.getInt32LE(buffer, index);
3130
+ index += 4;
3012
3131
  if (totalSize < 4 + 4 + 4 + 1) {
3013
3132
  throw new BSONError('code_w_scope total size shorter minimum expected length');
3014
3133
  }
3015
- const stringSize = buffer[index++] |
3016
- (buffer[index++] << 8) |
3017
- (buffer[index++] << 16) |
3018
- (buffer[index++] << 24);
3134
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3135
+ index += 4;
3019
3136
  if (stringSize <= 0 ||
3020
3137
  stringSize > buffer.length - index ||
3021
3138
  buffer[index + stringSize - 1] !== 0) {
@@ -3024,10 +3141,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
3024
3141
  const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
3025
3142
  index = index + stringSize;
3026
3143
  const _index = index;
3027
- const objectSize = buffer[index] |
3028
- (buffer[index + 1] << 8) |
3029
- (buffer[index + 2] << 16) |
3030
- (buffer[index + 3] << 24);
3144
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
3031
3145
  const scopeObject = deserializeObject(buffer, _index, options, false);
3032
3146
  index = index + objectSize;
3033
3147
  if (totalSize < 4 + 4 + objectSize + stringSize) {
@@ -3039,10 +3153,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
3039
3153
  value = new Code(functionString, scopeObject);
3040
3154
  }
3041
3155
  else if (elementType === BSON_DATA_DBPOINTER) {
3042
- const stringSize = buffer[index++] |
3043
- (buffer[index++] << 8) |
3044
- (buffer[index++] << 16) |
3045
- (buffer[index++] << 24);
3156
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3157
+ index += 4;
3046
3158
  if (stringSize <= 0 ||
3047
3159
  stringSize > buffer.length - index ||
3048
3160
  buffer[index + stringSize - 1] !== 0)
@@ -3054,8 +3166,9 @@ function deserializeObject(buffer, index, options, isArray = false) {
3054
3166
  }
3055
3167
  const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, false);
3056
3168
  index = index + stringSize;
3057
- const oidBuffer = ByteUtils.allocate(12);
3058
- oidBuffer.set(buffer.subarray(index, index + 12), 0);
3169
+ const oidBuffer = ByteUtils.allocateUnsafe(12);
3170
+ for (let i = 0; i < 12; i++)
3171
+ oidBuffer[i] = buffer[index + i];
3059
3172
  const oid = new ObjectId(oidBuffer);
3060
3173
  index = index + 12;
3061
3174
  value = new DBRef(namespace, oid);
@@ -3100,17 +3213,11 @@ function serializeString(buffer, key, value, index) {
3100
3213
  index = index + numberOfWrittenBytes + 1;
3101
3214
  buffer[index - 1] = 0;
3102
3215
  const size = ByteUtils.encodeUTF8Into(buffer, value, index + 4);
3103
- buffer[index + 3] = ((size + 1) >> 24) & 0xff;
3104
- buffer[index + 2] = ((size + 1) >> 16) & 0xff;
3105
- buffer[index + 1] = ((size + 1) >> 8) & 0xff;
3106
- buffer[index] = (size + 1) & 0xff;
3216
+ NumberUtils.setInt32LE(buffer, index, size + 1);
3107
3217
  index = index + 4 + size;
3108
3218
  buffer[index++] = 0;
3109
3219
  return index;
3110
3220
  }
3111
- const NUMBER_SPACE = new DataView(new ArrayBuffer(8), 0, 8);
3112
- const FOUR_BYTE_VIEW_ON_NUMBER = new Uint8Array(NUMBER_SPACE.buffer, 0, 4);
3113
- const EIGHT_BYTE_VIEW_ON_NUMBER = new Uint8Array(NUMBER_SPACE.buffer, 0, 8);
3114
3221
  function serializeNumber(buffer, key, value, index) {
3115
3222
  const isNegativeZero = Object.is(value, -0);
3116
3223
  const type = !isNegativeZero &&
@@ -3119,19 +3226,16 @@ function serializeNumber(buffer, key, value, index) {
3119
3226
  value >= BSON_INT32_MIN
3120
3227
  ? BSON_DATA_INT
3121
3228
  : BSON_DATA_NUMBER;
3122
- if (type === BSON_DATA_INT) {
3123
- NUMBER_SPACE.setInt32(0, value, true);
3124
- }
3125
- else {
3126
- NUMBER_SPACE.setFloat64(0, value, true);
3127
- }
3128
- const bytes = type === BSON_DATA_INT ? FOUR_BYTE_VIEW_ON_NUMBER : EIGHT_BYTE_VIEW_ON_NUMBER;
3129
3229
  buffer[index++] = type;
3130
3230
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3131
3231
  index = index + numberOfWrittenBytes;
3132
3232
  buffer[index++] = 0x00;
3133
- buffer.set(bytes, index);
3134
- index += bytes.byteLength;
3233
+ if (type === BSON_DATA_INT) {
3234
+ index += NumberUtils.setInt32LE(buffer, index, value);
3235
+ }
3236
+ else {
3237
+ index += NumberUtils.setFloat64LE(buffer, index, value);
3238
+ }
3135
3239
  return index;
3136
3240
  }
3137
3241
  function serializeBigInt(buffer, key, value, index) {
@@ -3139,9 +3243,7 @@ function serializeBigInt(buffer, key, value, index) {
3139
3243
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3140
3244
  index += numberOfWrittenBytes;
3141
3245
  buffer[index++] = 0;
3142
- NUMBER_SPACE.setBigInt64(0, value, true);
3143
- buffer.set(EIGHT_BYTE_VIEW_ON_NUMBER, index);
3144
- index += EIGHT_BYTE_VIEW_ON_NUMBER.byteLength;
3246
+ index += NumberUtils.setBigInt64LE(buffer, index, value);
3145
3247
  return index;
3146
3248
  }
3147
3249
  function serializeNull(buffer, key, _, index) {
@@ -3167,14 +3269,8 @@ function serializeDate(buffer, key, value, index) {
3167
3269
  const dateInMilis = Long.fromNumber(value.getTime());
3168
3270
  const lowBits = dateInMilis.getLowBits();
3169
3271
  const highBits = dateInMilis.getHighBits();
3170
- buffer[index++] = lowBits & 0xff;
3171
- buffer[index++] = (lowBits >> 8) & 0xff;
3172
- buffer[index++] = (lowBits >> 16) & 0xff;
3173
- buffer[index++] = (lowBits >> 24) & 0xff;
3174
- buffer[index++] = highBits & 0xff;
3175
- buffer[index++] = (highBits >> 8) & 0xff;
3176
- buffer[index++] = (highBits >> 16) & 0xff;
3177
- buffer[index++] = (highBits >> 24) & 0xff;
3272
+ index += NumberUtils.setInt32LE(buffer, index, lowBits);
3273
+ index += NumberUtils.setInt32LE(buffer, index, highBits);
3178
3274
  return index;
3179
3275
  }
3180
3276
  function serializeRegExp(buffer, key, value, index) {
@@ -3231,15 +3327,7 @@ function serializeObjectId(buffer, key, value, index) {
3231
3327
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3232
3328
  index = index + numberOfWrittenBytes;
3233
3329
  buffer[index++] = 0;
3234
- const idValue = value.id;
3235
- if (isUint8Array(idValue)) {
3236
- for (let i = 0; i < 12; i++) {
3237
- buffer[index++] = idValue[i];
3238
- }
3239
- }
3240
- else {
3241
- throw new BSONError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
3242
- }
3330
+ index += value.serializeInto(buffer, index);
3243
3331
  return index;
3244
3332
  }
3245
3333
  function serializeBuffer(buffer, key, value, index) {
@@ -3248,12 +3336,15 @@ function serializeBuffer(buffer, key, value, index) {
3248
3336
  index = index + numberOfWrittenBytes;
3249
3337
  buffer[index++] = 0;
3250
3338
  const size = value.length;
3251
- buffer[index++] = size & 0xff;
3252
- buffer[index++] = (size >> 8) & 0xff;
3253
- buffer[index++] = (size >> 16) & 0xff;
3254
- buffer[index++] = (size >> 24) & 0xff;
3339
+ index += NumberUtils.setInt32LE(buffer, index, size);
3255
3340
  buffer[index++] = BSON_BINARY_SUBTYPE_DEFAULT;
3256
- buffer.set(value, index);
3341
+ if (size <= 16) {
3342
+ for (let i = 0; i < size; i++)
3343
+ buffer[index + i] = value[i];
3344
+ }
3345
+ else {
3346
+ buffer.set(value, index);
3347
+ }
3257
3348
  index = index + size;
3258
3349
  return index;
3259
3350
  }
@@ -3275,7 +3366,8 @@ function serializeDecimal128(buffer, key, value, index) {
3275
3366
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3276
3367
  index = index + numberOfWrittenBytes;
3277
3368
  buffer[index++] = 0;
3278
- buffer.set(value.bytes.subarray(0, 16), index);
3369
+ for (let i = 0; i < 16; i++)
3370
+ buffer[index + i] = value.bytes[i];
3279
3371
  return index + 16;
3280
3372
  }
3281
3373
  function serializeLong(buffer, key, value, index) {
@@ -3286,14 +3378,8 @@ function serializeLong(buffer, key, value, index) {
3286
3378
  buffer[index++] = 0;
3287
3379
  const lowBits = value.getLowBits();
3288
3380
  const highBits = value.getHighBits();
3289
- buffer[index++] = lowBits & 0xff;
3290
- buffer[index++] = (lowBits >> 8) & 0xff;
3291
- buffer[index++] = (lowBits >> 16) & 0xff;
3292
- buffer[index++] = (lowBits >> 24) & 0xff;
3293
- buffer[index++] = highBits & 0xff;
3294
- buffer[index++] = (highBits >> 8) & 0xff;
3295
- buffer[index++] = (highBits >> 16) & 0xff;
3296
- buffer[index++] = (highBits >> 24) & 0xff;
3381
+ index += NumberUtils.setInt32LE(buffer, index, lowBits);
3382
+ index += NumberUtils.setInt32LE(buffer, index, highBits);
3297
3383
  return index;
3298
3384
  }
3299
3385
  function serializeInt32(buffer, key, value, index) {
@@ -3302,10 +3388,7 @@ function serializeInt32(buffer, key, value, index) {
3302
3388
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3303
3389
  index = index + numberOfWrittenBytes;
3304
3390
  buffer[index++] = 0;
3305
- buffer[index++] = value & 0xff;
3306
- buffer[index++] = (value >> 8) & 0xff;
3307
- buffer[index++] = (value >> 16) & 0xff;
3308
- buffer[index++] = (value >> 24) & 0xff;
3391
+ index += NumberUtils.setInt32LE(buffer, index, value);
3309
3392
  return index;
3310
3393
  }
3311
3394
  function serializeDouble(buffer, key, value, index) {
@@ -3313,9 +3396,7 @@ function serializeDouble(buffer, key, value, index) {
3313
3396
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3314
3397
  index = index + numberOfWrittenBytes;
3315
3398
  buffer[index++] = 0;
3316
- NUMBER_SPACE.setFloat64(0, value.value, true);
3317
- buffer.set(EIGHT_BYTE_VIEW_ON_NUMBER, index);
3318
- index = index + 8;
3399
+ index += NumberUtils.setFloat64LE(buffer, index, value.value);
3319
3400
  return index;
3320
3401
  }
3321
3402
  function serializeFunction(buffer, key, value, index) {
@@ -3325,10 +3406,7 @@ function serializeFunction(buffer, key, value, index) {
3325
3406
  buffer[index++] = 0;
3326
3407
  const functionString = value.toString();
3327
3408
  const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3328
- buffer[index] = size & 0xff;
3329
- buffer[index + 1] = (size >> 8) & 0xff;
3330
- buffer[index + 2] = (size >> 16) & 0xff;
3331
- buffer[index + 3] = (size >> 24) & 0xff;
3409
+ NumberUtils.setInt32LE(buffer, index, size);
3332
3410
  index = index + 4 + size - 1;
3333
3411
  buffer[index++] = 0;
3334
3412
  return index;
@@ -3343,19 +3421,13 @@ function serializeCode(buffer, key, value, index, checkKeys = false, depth = 0,
3343
3421
  const functionString = value.code;
3344
3422
  index = index + 4;
3345
3423
  const codeSize = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3346
- buffer[index] = codeSize & 0xff;
3347
- buffer[index + 1] = (codeSize >> 8) & 0xff;
3348
- buffer[index + 2] = (codeSize >> 16) & 0xff;
3349
- buffer[index + 3] = (codeSize >> 24) & 0xff;
3424
+ NumberUtils.setInt32LE(buffer, index, codeSize);
3350
3425
  buffer[index + 4 + codeSize - 1] = 0;
3351
3426
  index = index + codeSize + 4;
3352
3427
  const endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path);
3353
3428
  index = endIndex - 1;
3354
3429
  const totalSize = endIndex - startIndex;
3355
- buffer[startIndex++] = totalSize & 0xff;
3356
- buffer[startIndex++] = (totalSize >> 8) & 0xff;
3357
- buffer[startIndex++] = (totalSize >> 16) & 0xff;
3358
- buffer[startIndex++] = (totalSize >> 24) & 0xff;
3430
+ startIndex += NumberUtils.setInt32LE(buffer, startIndex, totalSize);
3359
3431
  buffer[index++] = 0;
3360
3432
  }
3361
3433
  else {
@@ -3365,10 +3437,7 @@ function serializeCode(buffer, key, value, index, checkKeys = false, depth = 0,
3365
3437
  buffer[index++] = 0;
3366
3438
  const functionString = value.code.toString();
3367
3439
  const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3368
- buffer[index] = size & 0xff;
3369
- buffer[index + 1] = (size >> 8) & 0xff;
3370
- buffer[index + 2] = (size >> 16) & 0xff;
3371
- buffer[index + 3] = (size >> 24) & 0xff;
3440
+ NumberUtils.setInt32LE(buffer, index, size);
3372
3441
  index = index + 4 + size - 1;
3373
3442
  buffer[index++] = 0;
3374
3443
  }
@@ -3383,19 +3452,19 @@ function serializeBinary(buffer, key, value, index) {
3383
3452
  let size = value.position;
3384
3453
  if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY)
3385
3454
  size = size + 4;
3386
- buffer[index++] = size & 0xff;
3387
- buffer[index++] = (size >> 8) & 0xff;
3388
- buffer[index++] = (size >> 16) & 0xff;
3389
- buffer[index++] = (size >> 24) & 0xff;
3455
+ index += NumberUtils.setInt32LE(buffer, index, size);
3390
3456
  buffer[index++] = value.sub_type;
3391
3457
  if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
3392
3458
  size = size - 4;
3393
- buffer[index++] = size & 0xff;
3394
- buffer[index++] = (size >> 8) & 0xff;
3395
- buffer[index++] = (size >> 16) & 0xff;
3396
- buffer[index++] = (size >> 24) & 0xff;
3459
+ index += NumberUtils.setInt32LE(buffer, index, size);
3460
+ }
3461
+ if (size <= 16) {
3462
+ for (let i = 0; i < size; i++)
3463
+ buffer[index + i] = data[i];
3464
+ }
3465
+ else {
3466
+ buffer.set(data, index);
3397
3467
  }
3398
- buffer.set(data, index);
3399
3468
  index = index + value.position;
3400
3469
  return index;
3401
3470
  }
@@ -3405,12 +3474,9 @@ function serializeSymbol(buffer, key, value, index) {
3405
3474
  index = index + numberOfWrittenBytes;
3406
3475
  buffer[index++] = 0;
3407
3476
  const size = ByteUtils.encodeUTF8Into(buffer, value.value, index + 4) + 1;
3408
- buffer[index] = size & 0xff;
3409
- buffer[index + 1] = (size >> 8) & 0xff;
3410
- buffer[index + 2] = (size >> 16) & 0xff;
3411
- buffer[index + 3] = (size >> 24) & 0xff;
3477
+ NumberUtils.setInt32LE(buffer, index, size);
3412
3478
  index = index + 4 + size - 1;
3413
- buffer[index++] = 0x00;
3479
+ buffer[index++] = 0;
3414
3480
  return index;
3415
3481
  }
3416
3482
  function serializeDBRef(buffer, key, value, index, depth, serializeFunctions, path) {
@@ -3429,10 +3495,7 @@ function serializeDBRef(buffer, key, value, index, depth, serializeFunctions, pa
3429
3495
  output = Object.assign(output, value.fields);
3430
3496
  const endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions, true, path);
3431
3497
  const size = endIndex - startIndex;
3432
- buffer[startIndex++] = size & 0xff;
3433
- buffer[startIndex++] = (size >> 8) & 0xff;
3434
- buffer[startIndex++] = (size >> 16) & 0xff;
3435
- buffer[startIndex++] = (size >> 24) & 0xff;
3498
+ startIndex += NumberUtils.setInt32LE(buffer, index, size);
3436
3499
  return endIndex;
3437
3500
  }
3438
3501
  function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializeFunctions, ignoreUndefined, path) {
@@ -3568,7 +3631,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3568
3631
  if ('$' === key[0]) {
3569
3632
  throw new BSONError('key ' + key + " must not start with '$'");
3570
3633
  }
3571
- else if (~key.indexOf('.')) {
3634
+ else if (key.includes('.')) {
3572
3635
  throw new BSONError('key ' + key + " must not contain '.'");
3573
3636
  }
3574
3637
  }
@@ -3666,7 +3729,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3666
3729
  if ('$' === key[0]) {
3667
3730
  throw new BSONError('key ' + key + " must not start with '$'");
3668
3731
  }
3669
- else if (~key.indexOf('.')) {
3732
+ else if (key.includes('.')) {
3670
3733
  throw new BSONError('key ' + key + " must not contain '.'");
3671
3734
  }
3672
3735
  }
@@ -3750,10 +3813,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3750
3813
  path.delete(object);
3751
3814
  buffer[index++] = 0x00;
3752
3815
  const size = index - startingIndex;
3753
- buffer[startingIndex++] = size & 0xff;
3754
- buffer[startingIndex++] = (size >> 8) & 0xff;
3755
- buffer[startingIndex++] = (size >> 16) & 0xff;
3756
- buffer[startingIndex++] = (size >> 24) & 0xff;
3816
+ startingIndex += NumberUtils.setInt32LE(buffer, startingIndex, size);
3757
3817
  return index;
3758
3818
  }
3759
3819
 
@@ -4067,6 +4127,104 @@ EJSON.serialize = EJSONserialize;
4067
4127
  EJSON.deserialize = EJSONdeserialize;
4068
4128
  Object.freeze(EJSON);
4069
4129
 
4130
+ function getSize(source, offset) {
4131
+ if (source[offset + 3] > 127) {
4132
+ throw new BSONOffsetError('BSON size cannot be negative', offset);
4133
+ }
4134
+ return (source[offset] |
4135
+ (source[offset + 1] << 8) |
4136
+ (source[offset + 2] << 16) |
4137
+ (source[offset + 3] << 24));
4138
+ }
4139
+ function findNull(bytes, offset) {
4140
+ let nullTerminatorOffset = offset;
4141
+ for (; bytes[nullTerminatorOffset] !== 0x00; nullTerminatorOffset++)
4142
+ ;
4143
+ if (nullTerminatorOffset === bytes.length - 1) {
4144
+ throw new BSONOffsetError('Null terminator not found', offset);
4145
+ }
4146
+ return nullTerminatorOffset;
4147
+ }
4148
+ function parseToElements(bytes, startOffset = 0) {
4149
+ if (bytes.length < 5) {
4150
+ throw new BSONOffsetError(`Input must be at least 5 bytes, got ${bytes.length} bytes`, startOffset);
4151
+ }
4152
+ const documentSize = getSize(bytes, startOffset);
4153
+ if (documentSize > bytes.length - startOffset) {
4154
+ throw new BSONOffsetError(`Parsed documentSize (${documentSize} bytes) does not match input length (${bytes.length} bytes)`, startOffset);
4155
+ }
4156
+ if (bytes[startOffset + documentSize - 1] !== 0x00) {
4157
+ throw new BSONOffsetError('BSON documents must end in 0x00', startOffset + documentSize);
4158
+ }
4159
+ const elements = [];
4160
+ let offset = startOffset + 4;
4161
+ while (offset <= documentSize + startOffset) {
4162
+ const type = bytes[offset];
4163
+ offset += 1;
4164
+ if (type === 0) {
4165
+ if (offset - startOffset !== documentSize) {
4166
+ throw new BSONOffsetError(`Invalid 0x00 type byte`, offset);
4167
+ }
4168
+ break;
4169
+ }
4170
+ const nameOffset = offset;
4171
+ const nameLength = findNull(bytes, offset) - nameOffset;
4172
+ offset += nameLength + 1;
4173
+ let length;
4174
+ if (type === 1 || type === 18 || type === 9 || type === 17) {
4175
+ length = 8;
4176
+ }
4177
+ else if (type === 16) {
4178
+ length = 4;
4179
+ }
4180
+ else if (type === 7) {
4181
+ length = 12;
4182
+ }
4183
+ else if (type === 19) {
4184
+ length = 16;
4185
+ }
4186
+ else if (type === 8) {
4187
+ length = 1;
4188
+ }
4189
+ else if (type === 10 || type === 6 || type === 127 || type === 255) {
4190
+ length = 0;
4191
+ }
4192
+ else if (type === 11) {
4193
+ length = findNull(bytes, findNull(bytes, offset) + 1) + 1 - offset;
4194
+ }
4195
+ else if (type === 3 || type === 4 || type === 15) {
4196
+ length = getSize(bytes, offset);
4197
+ }
4198
+ else if (type === 2 ||
4199
+ type === 5 ||
4200
+ type === 12 ||
4201
+ type === 13 ||
4202
+ type === 14) {
4203
+ length = getSize(bytes, offset) + 4;
4204
+ if (type === 5) {
4205
+ length += 1;
4206
+ }
4207
+ if (type === 12) {
4208
+ length += 12;
4209
+ }
4210
+ }
4211
+ else {
4212
+ throw new BSONOffsetError(`Invalid 0x${type.toString(16).padStart(2, '0')} type byte`, offset);
4213
+ }
4214
+ if (length > documentSize) {
4215
+ throw new BSONOffsetError('value reports length larger than document', offset);
4216
+ }
4217
+ elements.push([type, nameOffset, nameLength, offset, length]);
4218
+ offset += length;
4219
+ }
4220
+ return elements;
4221
+ }
4222
+
4223
+ const onDemand = Object.create(null);
4224
+ onDemand.parseToElements = parseToElements;
4225
+ onDemand.BSONOffsetError = BSONOffsetError;
4226
+ Object.freeze(onDemand);
4227
+
4070
4228
  const MAXSIZE = 1024 * 1024 * 17;
4071
4229
  let buffer = ByteUtils.allocate(MAXSIZE);
4072
4230
  function setInternalBufferSize(size) {
@@ -4083,7 +4241,7 @@ function serialize(object, options = {}) {
4083
4241
  buffer = ByteUtils.allocate(minInternalBufferSize);
4084
4242
  }
4085
4243
  const serializationIndex = serializeInto(buffer, object, checkKeys, 0, 0, serializeFunctions, ignoreUndefined, null);
4086
- const finishedBuffer = ByteUtils.allocate(serializationIndex);
4244
+ const finishedBuffer = ByteUtils.allocateUnsafe(serializationIndex);
4087
4245
  finishedBuffer.set(buffer.subarray(0, serializationIndex), 0);
4088
4246
  return finishedBuffer;
4089
4247
  }
@@ -4110,10 +4268,7 @@ function deserializeStream(data, startIndex, numberOfDocuments, documents, docSt
4110
4268
  const bufferData = ByteUtils.toLocalBufferType(data);
4111
4269
  let index = startIndex;
4112
4270
  for (let i = 0; i < numberOfDocuments; i++) {
4113
- const size = bufferData[index] |
4114
- (bufferData[index + 1] << 8) |
4115
- (bufferData[index + 2] << 16) |
4116
- (bufferData[index + 3] << 24);
4271
+ const size = NumberUtils.getInt32LE(bufferData, index);
4117
4272
  internalOptions.index = index;
4118
4273
  documents[docStartIndex + i] = internalDeserialize(bufferData, internalOptions);
4119
4274
  index = index + size;
@@ -4146,6 +4301,7 @@ UUID: UUID,
4146
4301
  calculateObjectSize: calculateObjectSize,
4147
4302
  deserialize: deserialize,
4148
4303
  deserializeStream: deserializeStream,
4304
+ onDemand: onDemand,
4149
4305
  serialize: serialize,
4150
4306
  serializeWithBufferAndIndex: serializeWithBufferAndIndex,
4151
4307
  setInternalBufferSize: setInternalBufferSize
@@ -4175,6 +4331,7 @@ exports.UUID = UUID;
4175
4331
  exports.calculateObjectSize = calculateObjectSize;
4176
4332
  exports.deserialize = deserialize;
4177
4333
  exports.deserializeStream = deserializeStream;
4334
+ exports.onDemand = onDemand;
4178
4335
  exports.serialize = serialize;
4179
4336
  exports.serializeWithBufferAndIndex = serializeWithBufferAndIndex;
4180
4337
  exports.setInternalBufferSize = setInternalBufferSize;