bson 4.0.4 → 4.2.2
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/HISTORY.md +56 -1
- package/README.md +7 -9
- package/bower.json +1 -1
- package/bson.d.ts +983 -0
- package/dist/bson.browser.esm.js +7261 -5004
- package/dist/bson.browser.esm.js.map +1 -0
- package/dist/bson.browser.umd.js +7319 -5099
- package/dist/bson.browser.umd.js.map +1 -0
- package/dist/bson.bundle.js +8168 -9216
- package/dist/bson.bundle.js.map +1 -0
- package/dist/bson.esm.js +5643 -5409
- package/dist/bson.esm.js.map +1 -0
- package/etc/prepare.js +19 -0
- package/lib/binary.js +194 -377
- package/lib/binary.js.map +1 -0
- package/lib/bson.js +200 -243
- package/lib/bson.js.map +1 -0
- package/lib/code.js +36 -39
- package/lib/code.js.map +1 -0
- package/lib/constants.js +78 -203
- package/lib/constants.js.map +1 -0
- package/lib/db_ref.js +79 -79
- package/lib/db_ref.js.map +1 -0
- package/lib/decimal128.js +647 -760
- package/lib/decimal128.js.map +1 -0
- package/lib/double.js +61 -58
- package/lib/double.js.map +1 -0
- package/lib/ensure_buffer.js +22 -18
- package/lib/ensure_buffer.js.map +1 -0
- package/lib/extended_json.js +305 -322
- package/lib/extended_json.js.map +1 -0
- package/lib/float_parser.js +98 -104
- package/lib/float_parser.js.map +1 -0
- package/lib/int_32.js +45 -47
- package/lib/int_32.js.map +1 -0
- package/lib/long.js +876 -16
- package/lib/long.js.map +1 -0
- package/lib/map.js +123 -124
- package/lib/map.js.map +1 -0
- package/lib/max_key.js +21 -23
- package/lib/max_key.js.map +1 -0
- package/lib/min_key.js +21 -23
- package/lib/min_key.js.map +1 -0
- package/lib/objectid.js +264 -382
- package/lib/objectid.js.map +1 -0
- package/lib/parser/calculate_size.js +185 -224
- package/lib/parser/calculate_size.js.map +1 -0
- package/lib/parser/deserializer.js +543 -620
- package/lib/parser/deserializer.js.map +1 -0
- package/lib/parser/serializer.js +774 -918
- package/lib/parser/serializer.js.map +1 -0
- package/lib/parser/utils.js +81 -30
- package/lib/parser/utils.js.map +1 -0
- package/lib/regexp.js +54 -70
- package/lib/regexp.js.map +1 -0
- package/lib/symbol.js +40 -56
- package/lib/symbol.js.map +1 -0
- package/lib/timestamp.js +70 -95
- package/lib/timestamp.js.map +1 -0
- package/lib/uuid.js +48 -0
- package/lib/uuid.js.map +1 -0
- package/lib/validate_utf8.js +32 -33
- package/lib/validate_utf8.js.map +1 -0
- package/package.json +53 -31
- package/src/binary.ts +270 -0
- package/src/bson.ts +326 -0
- package/src/code.ts +57 -0
- package/src/constants.ts +104 -0
- package/src/db_ref.ts +115 -0
- package/src/decimal128.ts +801 -0
- package/src/double.ts +85 -0
- package/src/ensure_buffer.ts +26 -0
- package/src/extended_json.ts +395 -0
- package/src/float_parser.ts +152 -0
- package/src/int_32.ts +64 -0
- package/src/long.ts +1000 -0
- package/src/map.ts +139 -0
- package/src/max_key.ts +33 -0
- package/src/min_key.ts +33 -0
- package/src/objectid.ts +377 -0
- package/src/parser/calculate_size.ts +230 -0
- package/src/parser/deserializer.ts +655 -0
- package/src/parser/serializer.ts +1069 -0
- package/src/parser/utils.ts +93 -0
- package/src/regexp.ts +92 -0
- package/src/symbol.ts +57 -0
- package/src/timestamp.ts +103 -0
- package/src/uuid.ts +57 -0
- package/src/validate_utf8.ts +47 -0
- package/lib/fnv1a.js +0 -48
|
@@ -1,640 +1,563 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deserialize = void 0;
|
|
4
|
+
const buffer_1 = require("buffer");
|
|
5
|
+
const binary_1 = require("../binary");
|
|
6
|
+
const code_1 = require("../code");
|
|
7
|
+
const constants = require("../constants");
|
|
8
|
+
const db_ref_1 = require("../db_ref");
|
|
9
|
+
const decimal128_1 = require("../decimal128");
|
|
10
|
+
const double_1 = require("../double");
|
|
11
|
+
const int_32_1 = require("../int_32");
|
|
12
|
+
const long_1 = require("../long");
|
|
13
|
+
const max_key_1 = require("../max_key");
|
|
14
|
+
const min_key_1 = require("../min_key");
|
|
15
|
+
const objectid_1 = require("../objectid");
|
|
16
|
+
const regexp_1 = require("../regexp");
|
|
17
|
+
const symbol_1 = require("../symbol");
|
|
18
|
+
const timestamp_1 = require("../timestamp");
|
|
19
|
+
const validate_utf8_1 = require("../validate_utf8");
|
|
20
20
|
// Internal long versions
|
|
21
|
-
const JS_INT_MAX_LONG = Long.fromNumber(constants.JS_INT_MAX);
|
|
22
|
-
const JS_INT_MIN_LONG = Long.fromNumber(constants.JS_INT_MIN);
|
|
23
|
-
|
|
21
|
+
const JS_INT_MAX_LONG = long_1.Long.fromNumber(constants.JS_INT_MAX);
|
|
22
|
+
const JS_INT_MIN_LONG = long_1.Long.fromNumber(constants.JS_INT_MIN);
|
|
24
23
|
const functionCache = {};
|
|
25
|
-
|
|
26
24
|
function deserialize(buffer, options, isArray) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
buffer[index] |
|
|
32
|
-
(buffer[index + 1] << 8) |
|
|
33
|
-
(buffer[index + 2] << 16) |
|
|
34
|
-
(buffer[index + 3] << 24);
|
|
35
|
-
|
|
36
|
-
if (size < 5) {
|
|
37
|
-
throw new Error(`bson size must be >= 5, is ${size}`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (options.allowObjectSmallerThanBufferSize && buffer.length < size) {
|
|
41
|
-
throw new Error(`buffer length ${buffer.length} must be >= bson size ${size}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!options.allowObjectSmallerThanBufferSize && buffer.length !== size) {
|
|
45
|
-
throw new Error(`buffer length ${buffer.length} must === bson size ${size}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (size + index > buffer.length) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
`(bson size ${size} + options.index ${index} must be <= buffer length ${Buffer.byteLength(
|
|
51
|
-
buffer
|
|
52
|
-
)})`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Illegal end value
|
|
57
|
-
if (buffer[index + size - 1] !== 0) {
|
|
58
|
-
throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00");
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Start deserializtion
|
|
62
|
-
return deserializeObject(buffer, index, options, isArray);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function deserializeObject(buffer, index, options, isArray) {
|
|
66
|
-
const evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
|
|
67
|
-
const cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
|
|
68
|
-
const cacheFunctionsCrc32 =
|
|
69
|
-
options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32'];
|
|
70
|
-
|
|
71
|
-
if (!cacheFunctionsCrc32) var crc32 = null;
|
|
72
|
-
|
|
73
|
-
const fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw'];
|
|
74
|
-
|
|
75
|
-
// Return raw bson buffer instead of parsing it
|
|
76
|
-
const raw = options['raw'] == null ? false : options['raw'];
|
|
77
|
-
|
|
78
|
-
// Return BSONRegExp objects instead of native regular expressions
|
|
79
|
-
const bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false;
|
|
80
|
-
|
|
81
|
-
// Controls the promotion of values vs wrapper classes
|
|
82
|
-
const promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
|
|
83
|
-
const promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
|
|
84
|
-
const promoteValues = options['promoteValues'] == null ? true : options['promoteValues'];
|
|
85
|
-
|
|
86
|
-
// Set the start index
|
|
87
|
-
let startIndex = index;
|
|
88
|
-
|
|
89
|
-
// Validate that we have at least 4 bytes of buffer
|
|
90
|
-
if (buffer.length < 5) throw new Error('corrupt bson message < 5 bytes long');
|
|
91
|
-
|
|
92
|
-
// Read the document size
|
|
93
|
-
const size =
|
|
94
|
-
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
|
|
95
|
-
|
|
96
|
-
// Ensure buffer is valid size
|
|
97
|
-
if (size < 5 || size > buffer.length) throw new Error('corrupt bson message');
|
|
98
|
-
|
|
99
|
-
// Create holding object
|
|
100
|
-
const object = isArray ? [] : {};
|
|
101
|
-
// Used for arrays to skip having to perform utf8 decoding
|
|
102
|
-
let arrayIndex = 0;
|
|
103
|
-
let done = false;
|
|
104
|
-
|
|
105
|
-
// While we have more left data left keep parsing
|
|
106
|
-
while (!done) {
|
|
107
|
-
// Read the type
|
|
108
|
-
const elementType = buffer[index++];
|
|
109
|
-
|
|
110
|
-
// If we get a zero it's the last byte, exit
|
|
111
|
-
if (elementType === 0) break;
|
|
112
|
-
|
|
113
|
-
// Get the start search index
|
|
114
|
-
let i = index;
|
|
115
|
-
// Locate the end of the c string
|
|
116
|
-
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
117
|
-
i++;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// If are at the end of the buffer there is a problem with the document
|
|
121
|
-
if (i >= Buffer.byteLength(buffer)) throw new Error('Bad BSON Document: illegal CString');
|
|
122
|
-
const name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i);
|
|
123
|
-
|
|
124
|
-
index = i + 1;
|
|
125
|
-
|
|
126
|
-
if (elementType === constants.BSON_DATA_STRING) {
|
|
127
|
-
const stringSize =
|
|
128
|
-
buffer[index++] |
|
|
129
|
-
(buffer[index++] << 8) |
|
|
130
|
-
(buffer[index++] << 16) |
|
|
131
|
-
(buffer[index++] << 24);
|
|
132
|
-
if (
|
|
133
|
-
stringSize <= 0 ||
|
|
134
|
-
stringSize > buffer.length - index ||
|
|
135
|
-
buffer[index + stringSize - 1] !== 0
|
|
136
|
-
)
|
|
137
|
-
throw new Error('bad string length in bson');
|
|
138
|
-
|
|
139
|
-
if (!validateUtf8(buffer, index, index + stringSize - 1)) {
|
|
140
|
-
throw new Error('Invalid UTF-8 string in BSON document');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const s = buffer.toString('utf8', index, index + stringSize - 1);
|
|
144
|
-
|
|
145
|
-
object[name] = s;
|
|
146
|
-
index = index + stringSize;
|
|
147
|
-
} else if (elementType === constants.BSON_DATA_OID) {
|
|
148
|
-
const oid = Buffer.alloc(12);
|
|
149
|
-
buffer.copy(oid, 0, index, index + 12);
|
|
150
|
-
object[name] = new ObjectId(oid);
|
|
151
|
-
index = index + 12;
|
|
152
|
-
} else if (elementType === constants.BSON_DATA_INT && promoteValues === false) {
|
|
153
|
-
object[name] = new Int32(
|
|
154
|
-
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24)
|
|
155
|
-
);
|
|
156
|
-
} else if (elementType === constants.BSON_DATA_INT) {
|
|
157
|
-
object[name] =
|
|
158
|
-
buffer[index++] |
|
|
159
|
-
(buffer[index++] << 8) |
|
|
160
|
-
(buffer[index++] << 16) |
|
|
161
|
-
(buffer[index++] << 24);
|
|
162
|
-
} else if (elementType === constants.BSON_DATA_NUMBER && promoteValues === false) {
|
|
163
|
-
object[name] = new Double(buffer.readDoubleLE(index));
|
|
164
|
-
index = index + 8;
|
|
165
|
-
} else if (elementType === constants.BSON_DATA_NUMBER) {
|
|
166
|
-
object[name] = buffer.readDoubleLE(index);
|
|
167
|
-
index = index + 8;
|
|
168
|
-
} else if (elementType === constants.BSON_DATA_DATE) {
|
|
169
|
-
const lowBits =
|
|
170
|
-
buffer[index++] |
|
|
171
|
-
(buffer[index++] << 8) |
|
|
172
|
-
(buffer[index++] << 16) |
|
|
173
|
-
(buffer[index++] << 24);
|
|
174
|
-
const highBits =
|
|
175
|
-
buffer[index++] |
|
|
176
|
-
(buffer[index++] << 8) |
|
|
177
|
-
(buffer[index++] << 16) |
|
|
178
|
-
(buffer[index++] << 24);
|
|
179
|
-
object[name] = new Date(new Long(lowBits, highBits).toNumber());
|
|
180
|
-
} else if (elementType === constants.BSON_DATA_BOOLEAN) {
|
|
181
|
-
if (buffer[index] !== 0 && buffer[index] !== 1) throw new Error('illegal boolean type value');
|
|
182
|
-
object[name] = buffer[index++] === 1;
|
|
183
|
-
} else if (elementType === constants.BSON_DATA_OBJECT) {
|
|
184
|
-
const _index = index;
|
|
185
|
-
const objectSize =
|
|
186
|
-
buffer[index] |
|
|
187
|
-
(buffer[index + 1] << 8) |
|
|
188
|
-
(buffer[index + 2] << 16) |
|
|
189
|
-
(buffer[index + 3] << 24);
|
|
190
|
-
if (objectSize <= 0 || objectSize > buffer.length - index)
|
|
191
|
-
throw new Error('bad embedded document length in bson');
|
|
192
|
-
|
|
193
|
-
// We have a raw value
|
|
194
|
-
if (raw) {
|
|
195
|
-
object[name] = buffer.slice(index, index + objectSize);
|
|
196
|
-
} else {
|
|
197
|
-
object[name] = deserializeObject(buffer, _index, options, false);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
index = index + objectSize;
|
|
201
|
-
} else if (elementType === constants.BSON_DATA_ARRAY) {
|
|
202
|
-
const _index = index;
|
|
203
|
-
const objectSize =
|
|
204
|
-
buffer[index] |
|
|
25
|
+
options = options == null ? {} : options;
|
|
26
|
+
const index = options && options.index ? options.index : 0;
|
|
27
|
+
// Read the document size
|
|
28
|
+
const size = buffer[index] |
|
|
205
29
|
(buffer[index + 1] << 8) |
|
|
206
30
|
(buffer[index + 2] << 16) |
|
|
207
31
|
(buffer[index + 3] << 24);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
(buffer[
|
|
266
|
-
|
|
267
|
-
(buffer[index++] << 24);
|
|
268
|
-
const totalBinarySize = binarySize;
|
|
269
|
-
const subType = buffer[index++];
|
|
270
|
-
|
|
271
|
-
// Did we have a negative binary size, throw
|
|
272
|
-
if (binarySize < 0) throw new Error('Negative binary type element size found');
|
|
273
|
-
|
|
274
|
-
// Is the length longer than the document
|
|
275
|
-
if (binarySize > Buffer.byteLength(buffer))
|
|
276
|
-
throw new Error('Binary type size larger than document size');
|
|
277
|
-
|
|
278
|
-
// Decode as raw Buffer object if options specifies it
|
|
279
|
-
if (buffer['slice'] != null) {
|
|
280
|
-
// If we have subtype 2 skip the 4 bytes for the size
|
|
281
|
-
if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
|
|
282
|
-
binarySize =
|
|
283
|
-
buffer[index++] |
|
|
284
|
-
(buffer[index++] << 8) |
|
|
285
|
-
(buffer[index++] << 16) |
|
|
286
|
-
(buffer[index++] << 24);
|
|
287
|
-
if (binarySize < 0)
|
|
288
|
-
throw new Error('Negative binary type element size found for subtype 0x02');
|
|
289
|
-
if (binarySize > totalBinarySize - 4)
|
|
290
|
-
throw new Error('Binary type with subtype 0x02 contains to long binary size');
|
|
291
|
-
if (binarySize < totalBinarySize - 4)
|
|
292
|
-
throw new Error('Binary type with subtype 0x02 contains to short binary size');
|
|
32
|
+
if (size < 5) {
|
|
33
|
+
throw new Error(`bson size must be >= 5, is ${size}`);
|
|
34
|
+
}
|
|
35
|
+
if (options.allowObjectSmallerThanBufferSize && buffer.length < size) {
|
|
36
|
+
throw new Error(`buffer length ${buffer.length} must be >= bson size ${size}`);
|
|
37
|
+
}
|
|
38
|
+
if (!options.allowObjectSmallerThanBufferSize && buffer.length !== size) {
|
|
39
|
+
throw new Error(`buffer length ${buffer.length} must === bson size ${size}`);
|
|
40
|
+
}
|
|
41
|
+
if (size + index > buffer.byteLength) {
|
|
42
|
+
throw new Error(`(bson size ${size} + options.index ${index} must be <= buffer length ${buffer.byteLength})`);
|
|
43
|
+
}
|
|
44
|
+
// Illegal end value
|
|
45
|
+
if (buffer[index + size - 1] !== 0) {
|
|
46
|
+
throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00");
|
|
47
|
+
}
|
|
48
|
+
// Start deserializtion
|
|
49
|
+
return deserializeObject(buffer, index, options, isArray);
|
|
50
|
+
}
|
|
51
|
+
exports.deserialize = deserialize;
|
|
52
|
+
function deserializeObject(buffer, index, options, isArray = false) {
|
|
53
|
+
const evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
|
|
54
|
+
const cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
|
|
55
|
+
const fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw'];
|
|
56
|
+
// Return raw bson buffer instead of parsing it
|
|
57
|
+
const raw = options['raw'] == null ? false : options['raw'];
|
|
58
|
+
// Return BSONRegExp objects instead of native regular expressions
|
|
59
|
+
const bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false;
|
|
60
|
+
// Controls the promotion of values vs wrapper classes
|
|
61
|
+
const promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
|
|
62
|
+
const promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
|
|
63
|
+
const promoteValues = options['promoteValues'] == null ? true : options['promoteValues'];
|
|
64
|
+
// Set the start index
|
|
65
|
+
const startIndex = index;
|
|
66
|
+
// Validate that we have at least 4 bytes of buffer
|
|
67
|
+
if (buffer.length < 5)
|
|
68
|
+
throw new Error('corrupt bson message < 5 bytes long');
|
|
69
|
+
// Read the document size
|
|
70
|
+
const size = buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
|
|
71
|
+
// Ensure buffer is valid size
|
|
72
|
+
if (size < 5 || size > buffer.length)
|
|
73
|
+
throw new Error('corrupt bson message');
|
|
74
|
+
// Create holding object
|
|
75
|
+
const object = isArray ? [] : {};
|
|
76
|
+
// Used for arrays to skip having to perform utf8 decoding
|
|
77
|
+
let arrayIndex = 0;
|
|
78
|
+
const done = false;
|
|
79
|
+
// While we have more left data left keep parsing
|
|
80
|
+
while (!done) {
|
|
81
|
+
// Read the type
|
|
82
|
+
const elementType = buffer[index++];
|
|
83
|
+
// If we get a zero it's the last byte, exit
|
|
84
|
+
if (elementType === 0)
|
|
85
|
+
break;
|
|
86
|
+
// Get the start search index
|
|
87
|
+
let i = index;
|
|
88
|
+
// Locate the end of the c string
|
|
89
|
+
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
90
|
+
i++;
|
|
293
91
|
}
|
|
294
|
-
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
92
|
+
// If are at the end of the buffer there is a problem with the document
|
|
93
|
+
if (i >= buffer.byteLength)
|
|
94
|
+
throw new Error('Bad BSON Document: illegal CString');
|
|
95
|
+
const name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i);
|
|
96
|
+
index = i + 1;
|
|
97
|
+
if (elementType === constants.BSON_DATA_STRING) {
|
|
98
|
+
const stringSize = buffer[index++] |
|
|
99
|
+
(buffer[index++] << 8) |
|
|
100
|
+
(buffer[index++] << 16) |
|
|
101
|
+
(buffer[index++] << 24);
|
|
102
|
+
if (stringSize <= 0 ||
|
|
103
|
+
stringSize > buffer.length - index ||
|
|
104
|
+
buffer[index + stringSize - 1] !== 0)
|
|
105
|
+
throw new Error('bad string length in bson');
|
|
106
|
+
if (!validate_utf8_1.validateUtf8(buffer, index, index + stringSize - 1)) {
|
|
107
|
+
throw new Error('Invalid UTF-8 string in BSON document');
|
|
108
|
+
}
|
|
109
|
+
const s = buffer.toString('utf8', index, index + stringSize - 1);
|
|
110
|
+
object[name] = s;
|
|
111
|
+
index = index + stringSize;
|
|
299
112
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
// If we have subtype 2 skip the 4 bytes for the size
|
|
306
|
-
if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
|
|
307
|
-
binarySize =
|
|
308
|
-
buffer[index++] |
|
|
309
|
-
(buffer[index++] << 8) |
|
|
310
|
-
(buffer[index++] << 16) |
|
|
311
|
-
(buffer[index++] << 24);
|
|
312
|
-
if (binarySize < 0)
|
|
313
|
-
throw new Error('Negative binary type element size found for subtype 0x02');
|
|
314
|
-
if (binarySize > totalBinarySize - 4)
|
|
315
|
-
throw new Error('Binary type with subtype 0x02 contains to long binary size');
|
|
316
|
-
if (binarySize < totalBinarySize - 4)
|
|
317
|
-
throw new Error('Binary type with subtype 0x02 contains to short binary size');
|
|
113
|
+
else if (elementType === constants.BSON_DATA_OID) {
|
|
114
|
+
const oid = buffer_1.Buffer.alloc(12);
|
|
115
|
+
buffer.copy(oid, 0, index, index + 12);
|
|
116
|
+
object[name] = new objectid_1.ObjectId(oid);
|
|
117
|
+
index = index + 12;
|
|
318
118
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
for (i = 0; i < binarySize; i++) {
|
|
322
|
-
_buffer[i] = buffer[index + i];
|
|
119
|
+
else if (elementType === constants.BSON_DATA_INT && promoteValues === false) {
|
|
120
|
+
object[name] = new int_32_1.Int32(buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24));
|
|
323
121
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
122
|
+
else if (elementType === constants.BSON_DATA_INT) {
|
|
123
|
+
object[name] =
|
|
124
|
+
buffer[index++] |
|
|
125
|
+
(buffer[index++] << 8) |
|
|
126
|
+
(buffer[index++] << 16) |
|
|
127
|
+
(buffer[index++] << 24);
|
|
329
128
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
index = index + binarySize;
|
|
334
|
-
} else if (elementType === constants.BSON_DATA_REGEXP && bsonRegExp === false) {
|
|
335
|
-
// Get the start search index
|
|
336
|
-
i = index;
|
|
337
|
-
// Locate the end of the c string
|
|
338
|
-
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
339
|
-
i++;
|
|
340
|
-
}
|
|
341
|
-
// If are at the end of the buffer there is a problem with the document
|
|
342
|
-
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
|
|
343
|
-
// Return the C string
|
|
344
|
-
const source = buffer.toString('utf8', index, i);
|
|
345
|
-
// Create the regexp
|
|
346
|
-
index = i + 1;
|
|
347
|
-
|
|
348
|
-
// Get the start search index
|
|
349
|
-
i = index;
|
|
350
|
-
// Locate the end of the c string
|
|
351
|
-
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
352
|
-
i++;
|
|
353
|
-
}
|
|
354
|
-
// If are at the end of the buffer there is a problem with the document
|
|
355
|
-
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
|
|
356
|
-
// Return the C string
|
|
357
|
-
const regExpOptions = buffer.toString('utf8', index, i);
|
|
358
|
-
index = i + 1;
|
|
359
|
-
|
|
360
|
-
// For each option add the corresponding one for javascript
|
|
361
|
-
const optionsArray = new Array(regExpOptions.length);
|
|
362
|
-
|
|
363
|
-
// Parse options
|
|
364
|
-
for (i = 0; i < regExpOptions.length; i++) {
|
|
365
|
-
switch (regExpOptions[i]) {
|
|
366
|
-
case 'm':
|
|
367
|
-
optionsArray[i] = 'm';
|
|
368
|
-
break;
|
|
369
|
-
case 's':
|
|
370
|
-
optionsArray[i] = 'g';
|
|
371
|
-
break;
|
|
372
|
-
case 'i':
|
|
373
|
-
optionsArray[i] = 'i';
|
|
374
|
-
break;
|
|
129
|
+
else if (elementType === constants.BSON_DATA_NUMBER && promoteValues === false) {
|
|
130
|
+
object[name] = new double_1.Double(buffer.readDoubleLE(index));
|
|
131
|
+
index = index + 8;
|
|
375
132
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
} else if (elementType === constants.BSON_DATA_REGEXP && bsonRegExp === true) {
|
|
380
|
-
// Get the start search index
|
|
381
|
-
i = index;
|
|
382
|
-
// Locate the end of the c string
|
|
383
|
-
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
384
|
-
i++;
|
|
385
|
-
}
|
|
386
|
-
// If are at the end of the buffer there is a problem with the document
|
|
387
|
-
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
|
|
388
|
-
// Return the C string
|
|
389
|
-
const source = buffer.toString('utf8', index, i);
|
|
390
|
-
index = i + 1;
|
|
391
|
-
|
|
392
|
-
// Get the start search index
|
|
393
|
-
i = index;
|
|
394
|
-
// Locate the end of the c string
|
|
395
|
-
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
396
|
-
i++;
|
|
397
|
-
}
|
|
398
|
-
// If are at the end of the buffer there is a problem with the document
|
|
399
|
-
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString');
|
|
400
|
-
// Return the C string
|
|
401
|
-
const regExpOptions = buffer.toString('utf8', index, i);
|
|
402
|
-
index = i + 1;
|
|
403
|
-
|
|
404
|
-
// Set the object
|
|
405
|
-
object[name] = new BSONRegExp(source, regExpOptions);
|
|
406
|
-
} else if (elementType === constants.BSON_DATA_SYMBOL) {
|
|
407
|
-
const stringSize =
|
|
408
|
-
buffer[index++] |
|
|
409
|
-
(buffer[index++] << 8) |
|
|
410
|
-
(buffer[index++] << 16) |
|
|
411
|
-
(buffer[index++] << 24);
|
|
412
|
-
if (
|
|
413
|
-
stringSize <= 0 ||
|
|
414
|
-
stringSize > buffer.length - index ||
|
|
415
|
-
buffer[index + stringSize - 1] !== 0
|
|
416
|
-
)
|
|
417
|
-
throw new Error('bad string length in bson');
|
|
418
|
-
const symbol = buffer.toString('utf8', index, index + stringSize - 1);
|
|
419
|
-
object[name] = promoteValues ? symbol : new BSONSymbol(symbol);
|
|
420
|
-
index = index + stringSize;
|
|
421
|
-
} else if (elementType === constants.BSON_DATA_TIMESTAMP) {
|
|
422
|
-
const lowBits =
|
|
423
|
-
buffer[index++] |
|
|
424
|
-
(buffer[index++] << 8) |
|
|
425
|
-
(buffer[index++] << 16) |
|
|
426
|
-
(buffer[index++] << 24);
|
|
427
|
-
const highBits =
|
|
428
|
-
buffer[index++] |
|
|
429
|
-
(buffer[index++] << 8) |
|
|
430
|
-
(buffer[index++] << 16) |
|
|
431
|
-
(buffer[index++] << 24);
|
|
432
|
-
|
|
433
|
-
object[name] = new Timestamp(lowBits, highBits);
|
|
434
|
-
} else if (elementType === constants.BSON_DATA_MIN_KEY) {
|
|
435
|
-
object[name] = new MinKey();
|
|
436
|
-
} else if (elementType === constants.BSON_DATA_MAX_KEY) {
|
|
437
|
-
object[name] = new MaxKey();
|
|
438
|
-
} else if (elementType === constants.BSON_DATA_CODE) {
|
|
439
|
-
const stringSize =
|
|
440
|
-
buffer[index++] |
|
|
441
|
-
(buffer[index++] << 8) |
|
|
442
|
-
(buffer[index++] << 16) |
|
|
443
|
-
(buffer[index++] << 24);
|
|
444
|
-
if (
|
|
445
|
-
stringSize <= 0 ||
|
|
446
|
-
stringSize > buffer.length - index ||
|
|
447
|
-
buffer[index + stringSize - 1] !== 0
|
|
448
|
-
)
|
|
449
|
-
throw new Error('bad string length in bson');
|
|
450
|
-
const functionString = buffer.toString('utf8', index, index + stringSize - 1);
|
|
451
|
-
|
|
452
|
-
// If we are evaluating the functions
|
|
453
|
-
if (evalFunctions) {
|
|
454
|
-
// If we have cache enabled let's look for the md5 of the function in the cache
|
|
455
|
-
if (cacheFunctions) {
|
|
456
|
-
const hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString;
|
|
457
|
-
// Got to do this to avoid V8 deoptimizing the call due to finding eval
|
|
458
|
-
object[name] = isolateEvalWithHash(functionCache, hash, functionString, object);
|
|
459
|
-
} else {
|
|
460
|
-
object[name] = isolateEval(functionString);
|
|
133
|
+
else if (elementType === constants.BSON_DATA_NUMBER) {
|
|
134
|
+
object[name] = buffer.readDoubleLE(index);
|
|
135
|
+
index = index + 8;
|
|
461
136
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
(
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
137
|
+
else if (elementType === constants.BSON_DATA_DATE) {
|
|
138
|
+
const lowBits = buffer[index++] |
|
|
139
|
+
(buffer[index++] << 8) |
|
|
140
|
+
(buffer[index++] << 16) |
|
|
141
|
+
(buffer[index++] << 24);
|
|
142
|
+
const highBits = buffer[index++] |
|
|
143
|
+
(buffer[index++] << 8) |
|
|
144
|
+
(buffer[index++] << 16) |
|
|
145
|
+
(buffer[index++] << 24);
|
|
146
|
+
object[name] = new Date(new long_1.Long(lowBits, highBits).toNumber());
|
|
147
|
+
}
|
|
148
|
+
else if (elementType === constants.BSON_DATA_BOOLEAN) {
|
|
149
|
+
if (buffer[index] !== 0 && buffer[index] !== 1)
|
|
150
|
+
throw new Error('illegal boolean type value');
|
|
151
|
+
object[name] = buffer[index++] === 1;
|
|
152
|
+
}
|
|
153
|
+
else if (elementType === constants.BSON_DATA_OBJECT) {
|
|
154
|
+
const _index = index;
|
|
155
|
+
const objectSize = buffer[index] |
|
|
156
|
+
(buffer[index + 1] << 8) |
|
|
157
|
+
(buffer[index + 2] << 16) |
|
|
158
|
+
(buffer[index + 3] << 24);
|
|
159
|
+
if (objectSize <= 0 || objectSize > buffer.length - index)
|
|
160
|
+
throw new Error('bad embedded document length in bson');
|
|
161
|
+
// We have a raw value
|
|
162
|
+
if (raw) {
|
|
163
|
+
object[name] = buffer.slice(index, index + objectSize);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
object[name] = deserializeObject(buffer, _index, options, false);
|
|
167
|
+
}
|
|
168
|
+
index = index + objectSize;
|
|
169
|
+
}
|
|
170
|
+
else if (elementType === constants.BSON_DATA_ARRAY) {
|
|
171
|
+
const _index = index;
|
|
172
|
+
const objectSize = buffer[index] |
|
|
173
|
+
(buffer[index + 1] << 8) |
|
|
174
|
+
(buffer[index + 2] << 16) |
|
|
175
|
+
(buffer[index + 3] << 24);
|
|
176
|
+
let arrayOptions = options;
|
|
177
|
+
// Stop index
|
|
178
|
+
const stopIndex = index + objectSize;
|
|
179
|
+
// All elements of array to be returned as raw bson
|
|
180
|
+
if (fieldsAsRaw && fieldsAsRaw[name]) {
|
|
181
|
+
arrayOptions = {};
|
|
182
|
+
for (const n in options) {
|
|
183
|
+
arrayOptions[n] = options[n];
|
|
184
|
+
}
|
|
185
|
+
arrayOptions['raw'] = true;
|
|
186
|
+
}
|
|
187
|
+
object[name] = deserializeObject(buffer, _index, arrayOptions, true);
|
|
188
|
+
index = index + objectSize;
|
|
189
|
+
if (buffer[index - 1] !== 0)
|
|
190
|
+
throw new Error('invalid array terminator byte');
|
|
191
|
+
if (index !== stopIndex)
|
|
192
|
+
throw new Error('corrupted array bson');
|
|
193
|
+
}
|
|
194
|
+
else if (elementType === constants.BSON_DATA_UNDEFINED) {
|
|
195
|
+
object[name] = undefined;
|
|
196
|
+
}
|
|
197
|
+
else if (elementType === constants.BSON_DATA_NULL) {
|
|
198
|
+
object[name] = null;
|
|
199
|
+
}
|
|
200
|
+
else if (elementType === constants.BSON_DATA_LONG) {
|
|
201
|
+
// Unpack the low and high bits
|
|
202
|
+
const lowBits = buffer[index++] |
|
|
203
|
+
(buffer[index++] << 8) |
|
|
204
|
+
(buffer[index++] << 16) |
|
|
205
|
+
(buffer[index++] << 24);
|
|
206
|
+
const highBits = buffer[index++] |
|
|
207
|
+
(buffer[index++] << 8) |
|
|
208
|
+
(buffer[index++] << 16) |
|
|
209
|
+
(buffer[index++] << 24);
|
|
210
|
+
const long = new long_1.Long(lowBits, highBits);
|
|
211
|
+
// Promote the long if possible
|
|
212
|
+
if (promoteLongs && promoteValues === true) {
|
|
213
|
+
object[name] =
|
|
214
|
+
long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
|
|
215
|
+
? long.toNumber()
|
|
216
|
+
: long;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
object[name] = long;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (elementType === constants.BSON_DATA_DECIMAL128) {
|
|
223
|
+
// Buffer to contain the decimal bytes
|
|
224
|
+
const bytes = buffer_1.Buffer.alloc(16);
|
|
225
|
+
// Copy the next 16 bytes into the bytes buffer
|
|
226
|
+
buffer.copy(bytes, 0, index, index + 16);
|
|
227
|
+
// Update index
|
|
228
|
+
index = index + 16;
|
|
229
|
+
// Assign the new Decimal128 value
|
|
230
|
+
const decimal128 = new decimal128_1.Decimal128(bytes);
|
|
231
|
+
// If we have an alternative mapper use that
|
|
232
|
+
if ('toObject' in decimal128 && typeof decimal128.toObject === 'function') {
|
|
233
|
+
object[name] = decimal128.toObject();
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
object[name] = decimal128;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else if (elementType === constants.BSON_DATA_BINARY) {
|
|
240
|
+
let binarySize = buffer[index++] |
|
|
241
|
+
(buffer[index++] << 8) |
|
|
242
|
+
(buffer[index++] << 16) |
|
|
243
|
+
(buffer[index++] << 24);
|
|
244
|
+
const totalBinarySize = binarySize;
|
|
245
|
+
const subType = buffer[index++];
|
|
246
|
+
// Did we have a negative binary size, throw
|
|
247
|
+
if (binarySize < 0)
|
|
248
|
+
throw new Error('Negative binary type element size found');
|
|
249
|
+
// Is the length longer than the document
|
|
250
|
+
if (binarySize > buffer.byteLength)
|
|
251
|
+
throw new Error('Binary type size larger than document size');
|
|
252
|
+
// Decode as raw Buffer object if options specifies it
|
|
253
|
+
if (buffer['slice'] != null) {
|
|
254
|
+
// If we have subtype 2 skip the 4 bytes for the size
|
|
255
|
+
if (subType === binary_1.Binary.SUBTYPE_BYTE_ARRAY) {
|
|
256
|
+
binarySize =
|
|
257
|
+
buffer[index++] |
|
|
258
|
+
(buffer[index++] << 8) |
|
|
259
|
+
(buffer[index++] << 16) |
|
|
260
|
+
(buffer[index++] << 24);
|
|
261
|
+
if (binarySize < 0)
|
|
262
|
+
throw new Error('Negative binary type element size found for subtype 0x02');
|
|
263
|
+
if (binarySize > totalBinarySize - 4)
|
|
264
|
+
throw new Error('Binary type with subtype 0x02 contains too long binary size');
|
|
265
|
+
if (binarySize < totalBinarySize - 4)
|
|
266
|
+
throw new Error('Binary type with subtype 0x02 contains too short binary size');
|
|
267
|
+
}
|
|
268
|
+
if (promoteBuffers && promoteValues) {
|
|
269
|
+
object[name] = buffer.slice(index, index + binarySize);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
object[name] = new binary_1.Binary(buffer.slice(index, index + binarySize), subType);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
const _buffer = buffer_1.Buffer.alloc(binarySize);
|
|
277
|
+
// If we have subtype 2 skip the 4 bytes for the size
|
|
278
|
+
if (subType === binary_1.Binary.SUBTYPE_BYTE_ARRAY) {
|
|
279
|
+
binarySize =
|
|
280
|
+
buffer[index++] |
|
|
281
|
+
(buffer[index++] << 8) |
|
|
282
|
+
(buffer[index++] << 16) |
|
|
283
|
+
(buffer[index++] << 24);
|
|
284
|
+
if (binarySize < 0)
|
|
285
|
+
throw new Error('Negative binary type element size found for subtype 0x02');
|
|
286
|
+
if (binarySize > totalBinarySize - 4)
|
|
287
|
+
throw new Error('Binary type with subtype 0x02 contains too long binary size');
|
|
288
|
+
if (binarySize < totalBinarySize - 4)
|
|
289
|
+
throw new Error('Binary type with subtype 0x02 contains too short binary size');
|
|
290
|
+
}
|
|
291
|
+
// Copy the data
|
|
292
|
+
for (i = 0; i < binarySize; i++) {
|
|
293
|
+
_buffer[i] = buffer[index + i];
|
|
294
|
+
}
|
|
295
|
+
if (promoteBuffers && promoteValues) {
|
|
296
|
+
object[name] = _buffer;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
object[name] = new binary_1.Binary(_buffer, subType);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// Update the index
|
|
303
|
+
index = index + binarySize;
|
|
304
|
+
}
|
|
305
|
+
else if (elementType === constants.BSON_DATA_REGEXP && bsonRegExp === false) {
|
|
306
|
+
// Get the start search index
|
|
307
|
+
i = index;
|
|
308
|
+
// Locate the end of the c string
|
|
309
|
+
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
310
|
+
i++;
|
|
311
|
+
}
|
|
312
|
+
// If are at the end of the buffer there is a problem with the document
|
|
313
|
+
if (i >= buffer.length)
|
|
314
|
+
throw new Error('Bad BSON Document: illegal CString');
|
|
315
|
+
// Return the C string
|
|
316
|
+
const source = buffer.toString('utf8', index, i);
|
|
317
|
+
// Create the regexp
|
|
318
|
+
index = i + 1;
|
|
319
|
+
// Get the start search index
|
|
320
|
+
i = index;
|
|
321
|
+
// Locate the end of the c string
|
|
322
|
+
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
323
|
+
i++;
|
|
324
|
+
}
|
|
325
|
+
// If are at the end of the buffer there is a problem with the document
|
|
326
|
+
if (i >= buffer.length)
|
|
327
|
+
throw new Error('Bad BSON Document: illegal CString');
|
|
328
|
+
// Return the C string
|
|
329
|
+
const regExpOptions = buffer.toString('utf8', index, i);
|
|
330
|
+
index = i + 1;
|
|
331
|
+
// For each option add the corresponding one for javascript
|
|
332
|
+
const optionsArray = new Array(regExpOptions.length);
|
|
333
|
+
// Parse options
|
|
334
|
+
for (i = 0; i < regExpOptions.length; i++) {
|
|
335
|
+
switch (regExpOptions[i]) {
|
|
336
|
+
case 'm':
|
|
337
|
+
optionsArray[i] = 'm';
|
|
338
|
+
break;
|
|
339
|
+
case 's':
|
|
340
|
+
optionsArray[i] = 'g';
|
|
341
|
+
break;
|
|
342
|
+
case 'i':
|
|
343
|
+
optionsArray[i] = 'i';
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
object[name] = new RegExp(source, optionsArray.join(''));
|
|
348
|
+
}
|
|
349
|
+
else if (elementType === constants.BSON_DATA_REGEXP && bsonRegExp === true) {
|
|
350
|
+
// Get the start search index
|
|
351
|
+
i = index;
|
|
352
|
+
// Locate the end of the c string
|
|
353
|
+
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
354
|
+
i++;
|
|
355
|
+
}
|
|
356
|
+
// If are at the end of the buffer there is a problem with the document
|
|
357
|
+
if (i >= buffer.length)
|
|
358
|
+
throw new Error('Bad BSON Document: illegal CString');
|
|
359
|
+
// Return the C string
|
|
360
|
+
const source = buffer.toString('utf8', index, i);
|
|
361
|
+
index = i + 1;
|
|
362
|
+
// Get the start search index
|
|
363
|
+
i = index;
|
|
364
|
+
// Locate the end of the c string
|
|
365
|
+
while (buffer[i] !== 0x00 && i < buffer.length) {
|
|
366
|
+
i++;
|
|
367
|
+
}
|
|
368
|
+
// If are at the end of the buffer there is a problem with the document
|
|
369
|
+
if (i >= buffer.length)
|
|
370
|
+
throw new Error('Bad BSON Document: illegal CString');
|
|
371
|
+
// Return the C string
|
|
372
|
+
const regExpOptions = buffer.toString('utf8', index, i);
|
|
373
|
+
index = i + 1;
|
|
374
|
+
// Set the object
|
|
375
|
+
object[name] = new regexp_1.BSONRegExp(source, regExpOptions);
|
|
376
|
+
}
|
|
377
|
+
else if (elementType === constants.BSON_DATA_SYMBOL) {
|
|
378
|
+
const stringSize = buffer[index++] |
|
|
379
|
+
(buffer[index++] << 8) |
|
|
380
|
+
(buffer[index++] << 16) |
|
|
381
|
+
(buffer[index++] << 24);
|
|
382
|
+
if (stringSize <= 0 ||
|
|
383
|
+
stringSize > buffer.length - index ||
|
|
384
|
+
buffer[index + stringSize - 1] !== 0)
|
|
385
|
+
throw new Error('bad string length in bson');
|
|
386
|
+
const symbol = buffer.toString('utf8', index, index + stringSize - 1);
|
|
387
|
+
object[name] = promoteValues ? symbol : new symbol_1.BSONSymbol(symbol);
|
|
388
|
+
index = index + stringSize;
|
|
389
|
+
}
|
|
390
|
+
else if (elementType === constants.BSON_DATA_TIMESTAMP) {
|
|
391
|
+
const lowBits = buffer[index++] |
|
|
392
|
+
(buffer[index++] << 8) |
|
|
393
|
+
(buffer[index++] << 16) |
|
|
394
|
+
(buffer[index++] << 24);
|
|
395
|
+
const highBits = buffer[index++] |
|
|
396
|
+
(buffer[index++] << 8) |
|
|
397
|
+
(buffer[index++] << 16) |
|
|
398
|
+
(buffer[index++] << 24);
|
|
399
|
+
object[name] = new timestamp_1.Timestamp(lowBits, highBits);
|
|
400
|
+
}
|
|
401
|
+
else if (elementType === constants.BSON_DATA_MIN_KEY) {
|
|
402
|
+
object[name] = new min_key_1.MinKey();
|
|
403
|
+
}
|
|
404
|
+
else if (elementType === constants.BSON_DATA_MAX_KEY) {
|
|
405
|
+
object[name] = new max_key_1.MaxKey();
|
|
406
|
+
}
|
|
407
|
+
else if (elementType === constants.BSON_DATA_CODE) {
|
|
408
|
+
const stringSize = buffer[index++] |
|
|
409
|
+
(buffer[index++] << 8) |
|
|
410
|
+
(buffer[index++] << 16) |
|
|
411
|
+
(buffer[index++] << 24);
|
|
412
|
+
if (stringSize <= 0 ||
|
|
413
|
+
stringSize > buffer.length - index ||
|
|
414
|
+
buffer[index + stringSize - 1] !== 0)
|
|
415
|
+
throw new Error('bad string length in bson');
|
|
416
|
+
const functionString = buffer.toString('utf8', index, index + stringSize - 1);
|
|
417
|
+
// If we are evaluating the functions
|
|
418
|
+
if (evalFunctions) {
|
|
419
|
+
// If we have cache enabled let's look for the md5 of the function in the cache
|
|
420
|
+
if (cacheFunctions) {
|
|
421
|
+
// Got to do this to avoid V8 deoptimizing the call due to finding eval
|
|
422
|
+
object[name] = isolateEval(functionString, functionCache, object);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
object[name] = isolateEval(functionString);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
object[name] = new code_1.Code(functionString);
|
|
430
|
+
}
|
|
431
|
+
// Update parse index position
|
|
432
|
+
index = index + stringSize;
|
|
433
|
+
}
|
|
434
|
+
else if (elementType === constants.BSON_DATA_CODE_W_SCOPE) {
|
|
435
|
+
const totalSize = buffer[index++] |
|
|
436
|
+
(buffer[index++] << 8) |
|
|
437
|
+
(buffer[index++] << 16) |
|
|
438
|
+
(buffer[index++] << 24);
|
|
439
|
+
// Element cannot be shorter than totalSize + stringSize + documentSize + terminator
|
|
440
|
+
if (totalSize < 4 + 4 + 4 + 1) {
|
|
441
|
+
throw new Error('code_w_scope total size shorter minimum expected length');
|
|
442
|
+
}
|
|
443
|
+
// Get the code string size
|
|
444
|
+
const stringSize = buffer[index++] |
|
|
445
|
+
(buffer[index++] << 8) |
|
|
446
|
+
(buffer[index++] << 16) |
|
|
447
|
+
(buffer[index++] << 24);
|
|
448
|
+
// Check if we have a valid string
|
|
449
|
+
if (stringSize <= 0 ||
|
|
450
|
+
stringSize > buffer.length - index ||
|
|
451
|
+
buffer[index + stringSize - 1] !== 0)
|
|
452
|
+
throw new Error('bad string length in bson');
|
|
453
|
+
// Javascript function
|
|
454
|
+
const functionString = buffer.toString('utf8', index, index + stringSize - 1);
|
|
455
|
+
// Update parse index position
|
|
456
|
+
index = index + stringSize;
|
|
457
|
+
// Parse the element
|
|
458
|
+
const _index = index;
|
|
459
|
+
// Decode the size of the object document
|
|
460
|
+
const objectSize = buffer[index] |
|
|
461
|
+
(buffer[index + 1] << 8) |
|
|
462
|
+
(buffer[index + 2] << 16) |
|
|
463
|
+
(buffer[index + 3] << 24);
|
|
464
|
+
// Decode the scope object
|
|
465
|
+
const scopeObject = deserializeObject(buffer, _index, options, false);
|
|
466
|
+
// Adjust the index
|
|
467
|
+
index = index + objectSize;
|
|
468
|
+
// Check if field length is too short
|
|
469
|
+
if (totalSize < 4 + 4 + objectSize + stringSize) {
|
|
470
|
+
throw new Error('code_w_scope total size is too short, truncating scope');
|
|
471
|
+
}
|
|
472
|
+
// Check if totalSize field is too long
|
|
473
|
+
if (totalSize > 4 + 4 + objectSize + stringSize) {
|
|
474
|
+
throw new Error('code_w_scope total size is too long, clips outer document');
|
|
475
|
+
}
|
|
476
|
+
// If we are evaluating the functions
|
|
477
|
+
if (evalFunctions) {
|
|
478
|
+
// If we have cache enabled let's look for the md5 of the function in the cache
|
|
479
|
+
if (cacheFunctions) {
|
|
480
|
+
// Got to do this to avoid V8 deoptimizing the call due to finding eval
|
|
481
|
+
object[name] = isolateEval(functionString, functionCache, object);
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
object[name] = isolateEval(functionString);
|
|
485
|
+
}
|
|
486
|
+
object[name].scope = scopeObject;
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
object[name] = new code_1.Code(functionString, scopeObject);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
else if (elementType === constants.BSON_DATA_DBPOINTER) {
|
|
493
|
+
// Get the code string size
|
|
494
|
+
const stringSize = buffer[index++] |
|
|
495
|
+
(buffer[index++] << 8) |
|
|
496
|
+
(buffer[index++] << 16) |
|
|
497
|
+
(buffer[index++] << 24);
|
|
498
|
+
// Check if we have a valid string
|
|
499
|
+
if (stringSize <= 0 ||
|
|
500
|
+
stringSize > buffer.length - index ||
|
|
501
|
+
buffer[index + stringSize - 1] !== 0)
|
|
502
|
+
throw new Error('bad string length in bson');
|
|
503
|
+
// Namespace
|
|
504
|
+
if (!validate_utf8_1.validateUtf8(buffer, index, index + stringSize - 1)) {
|
|
505
|
+
throw new Error('Invalid UTF-8 string in BSON document');
|
|
506
|
+
}
|
|
507
|
+
const namespace = buffer.toString('utf8', index, index + stringSize - 1);
|
|
508
|
+
// Update parse index position
|
|
509
|
+
index = index + stringSize;
|
|
510
|
+
// Read the oid
|
|
511
|
+
const oidBuffer = buffer_1.Buffer.alloc(12);
|
|
512
|
+
buffer.copy(oidBuffer, 0, index, index + 12);
|
|
513
|
+
const oid = new objectid_1.ObjectId(oidBuffer);
|
|
514
|
+
// Update the index
|
|
515
|
+
index = index + 12;
|
|
516
|
+
// Upgrade to DBRef type
|
|
517
|
+
object[name] = new db_ref_1.DBRef(namespace, oid);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
throw new Error('Detected unknown BSON type ' + elementType.toString(16) + ' for fieldname "' + name + '"');
|
|
530
521
|
}
|
|
531
|
-
|
|
532
|
-
object[name].scope = scopeObject;
|
|
533
|
-
} else {
|
|
534
|
-
object[name] = new Code(functionString, scopeObject);
|
|
535
|
-
}
|
|
536
|
-
} else if (elementType === constants.BSON_DATA_DBPOINTER) {
|
|
537
|
-
// Get the code string size
|
|
538
|
-
const stringSize =
|
|
539
|
-
buffer[index++] |
|
|
540
|
-
(buffer[index++] << 8) |
|
|
541
|
-
(buffer[index++] << 16) |
|
|
542
|
-
(buffer[index++] << 24);
|
|
543
|
-
// Check if we have a valid string
|
|
544
|
-
if (
|
|
545
|
-
stringSize <= 0 ||
|
|
546
|
-
stringSize > buffer.length - index ||
|
|
547
|
-
buffer[index + stringSize - 1] !== 0
|
|
548
|
-
)
|
|
549
|
-
throw new Error('bad string length in bson');
|
|
550
|
-
// Namespace
|
|
551
|
-
if (!validateUtf8(buffer, index, index + stringSize - 1)) {
|
|
552
|
-
throw new Error('Invalid UTF-8 string in BSON document');
|
|
553
|
-
}
|
|
554
|
-
const namespace = buffer.toString('utf8', index, index + stringSize - 1);
|
|
555
|
-
// Update parse index position
|
|
556
|
-
index = index + stringSize;
|
|
557
|
-
|
|
558
|
-
// Read the oid
|
|
559
|
-
const oidBuffer = Buffer.alloc(12);
|
|
560
|
-
buffer.copy(oidBuffer, 0, index, index + 12);
|
|
561
|
-
const oid = new ObjectId(oidBuffer);
|
|
562
|
-
|
|
563
|
-
// Update the index
|
|
564
|
-
index = index + 12;
|
|
565
|
-
|
|
566
|
-
// Upgrade to DBRef type
|
|
567
|
-
object[name] = new DBRef(namespace, oid);
|
|
568
|
-
} else {
|
|
569
|
-
throw new Error(
|
|
570
|
-
'Detected unknown BSON type ' +
|
|
571
|
-
elementType.toString(16) +
|
|
572
|
-
' for fieldname "' +
|
|
573
|
-
name +
|
|
574
|
-
'", are you using the latest BSON parser?'
|
|
575
|
-
);
|
|
576
522
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
return
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
return object;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* Ensure eval is isolated.
|
|
608
|
-
*
|
|
609
|
-
* @ignore
|
|
610
|
-
* @api private
|
|
611
|
-
*/
|
|
612
|
-
function isolateEvalWithHash(functionCache, hash, functionString, object) {
|
|
613
|
-
// Contains the value we are going to set
|
|
614
|
-
let value = null;
|
|
615
|
-
|
|
616
|
-
// Check for cache hit, eval if missing and return cached function
|
|
617
|
-
if (functionCache[hash] == null) {
|
|
618
|
-
eval('value = ' + functionString);
|
|
619
|
-
functionCache[hash] = value;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// Set the object
|
|
623
|
-
return functionCache[hash].bind(object);
|
|
523
|
+
// Check if the deserialization was against a valid array/object
|
|
524
|
+
if (size !== index - startIndex) {
|
|
525
|
+
if (isArray)
|
|
526
|
+
throw new Error('corrupt array bson');
|
|
527
|
+
throw new Error('corrupt object bson');
|
|
528
|
+
}
|
|
529
|
+
// check if object's $ keys are those of a DBRef
|
|
530
|
+
const dollarKeys = Object.keys(object).filter(k => k.startsWith('$'));
|
|
531
|
+
let valid = true;
|
|
532
|
+
dollarKeys.forEach(k => {
|
|
533
|
+
if (['$ref', '$id', '$db'].indexOf(k) === -1)
|
|
534
|
+
valid = false;
|
|
535
|
+
});
|
|
536
|
+
// if a $key not in "$ref", "$id", "$db", don't make a DBRef
|
|
537
|
+
if (!valid)
|
|
538
|
+
return object;
|
|
539
|
+
if (db_ref_1.isDBRefLike(object)) {
|
|
540
|
+
const copy = Object.assign({}, object);
|
|
541
|
+
delete copy.$ref;
|
|
542
|
+
delete copy.$id;
|
|
543
|
+
delete copy.$db;
|
|
544
|
+
return new db_ref_1.DBRef(object.$ref, object.$id, object.$db, copy);
|
|
545
|
+
}
|
|
546
|
+
return object;
|
|
624
547
|
}
|
|
625
|
-
|
|
626
548
|
/**
|
|
627
|
-
* Ensure eval is isolated.
|
|
549
|
+
* Ensure eval is isolated, store the result in functionCache.
|
|
628
550
|
*
|
|
629
|
-
* @
|
|
630
|
-
* @api private
|
|
551
|
+
* @internal
|
|
631
552
|
*/
|
|
632
|
-
function isolateEval(functionString) {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
553
|
+
function isolateEval(functionString, functionCache, object) {
|
|
554
|
+
if (!functionCache)
|
|
555
|
+
return new Function(functionString);
|
|
556
|
+
// Check for cache hit, eval if missing and return cached function
|
|
557
|
+
if (functionCache[functionString] == null) {
|
|
558
|
+
functionCache[functionString] = new Function(functionString);
|
|
559
|
+
}
|
|
560
|
+
// Set the object
|
|
561
|
+
return functionCache[functionString].bind(object);
|
|
638
562
|
}
|
|
639
|
-
|
|
640
|
-
module.exports = deserialize;
|
|
563
|
+
//# sourceMappingURL=deserializer.js.map
|