deserializer.js 30 KB

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