serializer.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. 'use strict';
  2. const Buffer = require('buffer').Buffer;
  3. const writeIEEE754 = require('../float_parser').writeIEEE754;
  4. const Long = require('../long');
  5. const Map = require('../map');
  6. const MinKey = require('../min_key');
  7. const Binary = require('../binary');
  8. const constants = require('../constants');
  9. const normalizedFunctionString = require('./utils').normalizedFunctionString;
  10. const regexp = /\x00/; // eslint-disable-line no-control-regex
  11. const ignoreKeys = new Set(['$db', '$ref', '$id', '$clusterTime']);
  12. // To ensure that 0.4 of node works correctly
  13. const isDate = function isDate(d) {
  14. return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]';
  15. };
  16. const isRegExp = function isRegExp(d) {
  17. return Object.prototype.toString.call(d) === '[object RegExp]';
  18. };
  19. function serializeString(buffer, key, value, index, isArray) {
  20. // Encode String type
  21. buffer[index++] = constants.BSON_DATA_STRING;
  22. // Number of written bytes
  23. const numberOfWrittenBytes = !isArray
  24. ? buffer.write(key, index, 'utf8')
  25. : buffer.write(key, index, 'ascii');
  26. // Encode the name
  27. index = index + numberOfWrittenBytes + 1;
  28. buffer[index - 1] = 0;
  29. // Write the string
  30. const size = buffer.write(value, index + 4, 'utf8');
  31. // Write the size of the string to buffer
  32. buffer[index + 3] = ((size + 1) >> 24) & 0xff;
  33. buffer[index + 2] = ((size + 1) >> 16) & 0xff;
  34. buffer[index + 1] = ((size + 1) >> 8) & 0xff;
  35. buffer[index] = (size + 1) & 0xff;
  36. // Update index
  37. index = index + 4 + size;
  38. // Write zero
  39. buffer[index++] = 0;
  40. return index;
  41. }
  42. function serializeNumber(buffer, key, value, index, isArray) {
  43. // We have an integer value
  44. if (
  45. Math.floor(value) === value &&
  46. value >= constants.JS_INT_MIN &&
  47. value <= constants.JS_INT_MAX
  48. ) {
  49. // If the value fits in 32 bits encode as int, if it fits in a double
  50. // encode it as a double, otherwise long
  51. if (value >= constants.BSON_INT32_MIN && value <= constants.BSON_INT32_MAX) {
  52. // Set int type 32 bits or less
  53. buffer[index++] = constants.BSON_DATA_INT;
  54. // Number of written bytes
  55. const numberOfWrittenBytes = !isArray
  56. ? buffer.write(key, index, 'utf8')
  57. : buffer.write(key, index, 'ascii');
  58. // Encode the name
  59. index = index + numberOfWrittenBytes;
  60. buffer[index++] = 0;
  61. // Write the int value
  62. buffer[index++] = value & 0xff;
  63. buffer[index++] = (value >> 8) & 0xff;
  64. buffer[index++] = (value >> 16) & 0xff;
  65. buffer[index++] = (value >> 24) & 0xff;
  66. } else if (value >= constants.JS_INT_MIN && value <= constants.JS_INT_MAX) {
  67. // Encode as double
  68. buffer[index++] = constants.BSON_DATA_NUMBER;
  69. // Number of written bytes
  70. const numberOfWrittenBytes = !isArray
  71. ? buffer.write(key, index, 'utf8')
  72. : buffer.write(key, index, 'ascii');
  73. // Encode the name
  74. index = index + numberOfWrittenBytes;
  75. buffer[index++] = 0;
  76. // Write float
  77. writeIEEE754(buffer, value, index, 'little', 52, 8);
  78. // Ajust index
  79. index = index + 8;
  80. } else {
  81. // Set long type
  82. buffer[index++] = constants.BSON_DATA_LONG;
  83. // Number of written bytes
  84. const numberOfWrittenBytes = !isArray
  85. ? buffer.write(key, index, 'utf8')
  86. : buffer.write(key, index, 'ascii');
  87. // Encode the name
  88. index = index + numberOfWrittenBytes;
  89. buffer[index++] = 0;
  90. const longVal = Long.fromNumber(value);
  91. const lowBits = longVal.getLowBits();
  92. const highBits = longVal.getHighBits();
  93. // Encode low bits
  94. buffer[index++] = lowBits & 0xff;
  95. buffer[index++] = (lowBits >> 8) & 0xff;
  96. buffer[index++] = (lowBits >> 16) & 0xff;
  97. buffer[index++] = (lowBits >> 24) & 0xff;
  98. // Encode high bits
  99. buffer[index++] = highBits & 0xff;
  100. buffer[index++] = (highBits >> 8) & 0xff;
  101. buffer[index++] = (highBits >> 16) & 0xff;
  102. buffer[index++] = (highBits >> 24) & 0xff;
  103. }
  104. } else {
  105. // Encode as double
  106. buffer[index++] = constants.BSON_DATA_NUMBER;
  107. // Number of written bytes
  108. const numberOfWrittenBytes = !isArray
  109. ? buffer.write(key, index, 'utf8')
  110. : buffer.write(key, index, 'ascii');
  111. // Encode the name
  112. index = index + numberOfWrittenBytes;
  113. buffer[index++] = 0;
  114. // Write float
  115. writeIEEE754(buffer, value, index, 'little', 52, 8);
  116. // Ajust index
  117. index = index + 8;
  118. }
  119. return index;
  120. }
  121. function serializeNull(buffer, key, value, index, isArray) {
  122. // Set long type
  123. buffer[index++] = constants.BSON_DATA_NULL;
  124. // Number of written bytes
  125. const numberOfWrittenBytes = !isArray
  126. ? buffer.write(key, index, 'utf8')
  127. : buffer.write(key, index, 'ascii');
  128. // Encode the name
  129. index = index + numberOfWrittenBytes;
  130. buffer[index++] = 0;
  131. return index;
  132. }
  133. function serializeBoolean(buffer, key, value, index, isArray) {
  134. // Write the type
  135. buffer[index++] = constants.BSON_DATA_BOOLEAN;
  136. // Number of written bytes
  137. const numberOfWrittenBytes = !isArray
  138. ? buffer.write(key, index, 'utf8')
  139. : buffer.write(key, index, 'ascii');
  140. // Encode the name
  141. index = index + numberOfWrittenBytes;
  142. buffer[index++] = 0;
  143. // Encode the boolean value
  144. buffer[index++] = value ? 1 : 0;
  145. return index;
  146. }
  147. function serializeDate(buffer, key, value, index, isArray) {
  148. // Write the type
  149. buffer[index++] = constants.BSON_DATA_DATE;
  150. // Number of written bytes
  151. const numberOfWrittenBytes = !isArray
  152. ? buffer.write(key, index, 'utf8')
  153. : buffer.write(key, index, 'ascii');
  154. // Encode the name
  155. index = index + numberOfWrittenBytes;
  156. buffer[index++] = 0;
  157. // Write the date
  158. const dateInMilis = Long.fromNumber(value.getTime());
  159. const lowBits = dateInMilis.getLowBits();
  160. const highBits = dateInMilis.getHighBits();
  161. // Encode low bits
  162. buffer[index++] = lowBits & 0xff;
  163. buffer[index++] = (lowBits >> 8) & 0xff;
  164. buffer[index++] = (lowBits >> 16) & 0xff;
  165. buffer[index++] = (lowBits >> 24) & 0xff;
  166. // Encode high bits
  167. buffer[index++] = highBits & 0xff;
  168. buffer[index++] = (highBits >> 8) & 0xff;
  169. buffer[index++] = (highBits >> 16) & 0xff;
  170. buffer[index++] = (highBits >> 24) & 0xff;
  171. return index;
  172. }
  173. function serializeRegExp(buffer, key, value, index, isArray) {
  174. // Write the type
  175. buffer[index++] = constants.BSON_DATA_REGEXP;
  176. // Number of written bytes
  177. const numberOfWrittenBytes = !isArray
  178. ? buffer.write(key, index, 'utf8')
  179. : buffer.write(key, index, 'ascii');
  180. // Encode the name
  181. index = index + numberOfWrittenBytes;
  182. buffer[index++] = 0;
  183. if (value.source && value.source.match(regexp) != null) {
  184. throw Error('value ' + value.source + ' must not contain null bytes');
  185. }
  186. // Adjust the index
  187. index = index + buffer.write(value.source, index, 'utf8');
  188. // Write zero
  189. buffer[index++] = 0x00;
  190. // Write the parameters
  191. if (value.ignoreCase) buffer[index++] = 0x69; // i
  192. if (value.global) buffer[index++] = 0x73; // s
  193. if (value.multiline) buffer[index++] = 0x6d; // m
  194. // Add ending zero
  195. buffer[index++] = 0x00;
  196. return index;
  197. }
  198. function serializeBSONRegExp(buffer, key, value, index, isArray) {
  199. // Write the type
  200. buffer[index++] = constants.BSON_DATA_REGEXP;
  201. // Number of written bytes
  202. const numberOfWrittenBytes = !isArray
  203. ? buffer.write(key, index, 'utf8')
  204. : buffer.write(key, index, 'ascii');
  205. // Encode the name
  206. index = index + numberOfWrittenBytes;
  207. buffer[index++] = 0;
  208. // Check the pattern for 0 bytes
  209. if (value.pattern.match(regexp) != null) {
  210. // The BSON spec doesn't allow keys with null bytes because keys are
  211. // null-terminated.
  212. throw Error('pattern ' + value.pattern + ' must not contain null bytes');
  213. }
  214. // Adjust the index
  215. index = index + buffer.write(value.pattern, index, 'utf8');
  216. // Write zero
  217. buffer[index++] = 0x00;
  218. // Write the options
  219. index =
  220. index +
  221. buffer.write(
  222. value.options
  223. .split('')
  224. .sort()
  225. .join(''),
  226. index,
  227. 'utf8'
  228. );
  229. // Add ending zero
  230. buffer[index++] = 0x00;
  231. return index;
  232. }
  233. function serializeMinMax(buffer, key, value, index, isArray) {
  234. // Write the type of either min or max key
  235. if (value === null) {
  236. buffer[index++] = constants.BSON_DATA_NULL;
  237. } else if (value instanceof MinKey) {
  238. buffer[index++] = constants.BSON_DATA_MIN_KEY;
  239. } else {
  240. buffer[index++] = constants.BSON_DATA_MAX_KEY;
  241. }
  242. // Number of written bytes
  243. const numberOfWrittenBytes = !isArray
  244. ? buffer.write(key, index, 'utf8')
  245. : buffer.write(key, index, 'ascii');
  246. // Encode the name
  247. index = index + numberOfWrittenBytes;
  248. buffer[index++] = 0;
  249. return index;
  250. }
  251. function serializeObjectId(buffer, key, value, index, isArray) {
  252. // Write the type
  253. buffer[index++] = constants.BSON_DATA_OID;
  254. // Number of written bytes
  255. const numberOfWrittenBytes = !isArray
  256. ? buffer.write(key, index, 'utf8')
  257. : buffer.write(key, index, 'ascii');
  258. // Encode the name
  259. index = index + numberOfWrittenBytes;
  260. buffer[index++] = 0;
  261. // Write the objectId into the shared buffer
  262. if (typeof value.id === 'string') {
  263. buffer.write(value.id, index, 'binary');
  264. } else if (value.id && value.id.copy) {
  265. value.id.copy(buffer, index, 0, 12);
  266. } else {
  267. throw new TypeError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
  268. }
  269. // Ajust index
  270. return index + 12;
  271. }
  272. function serializeBuffer(buffer, key, value, index, isArray) {
  273. // Write the type
  274. buffer[index++] = constants.BSON_DATA_BINARY;
  275. // Number of written bytes
  276. const numberOfWrittenBytes = !isArray
  277. ? buffer.write(key, index, 'utf8')
  278. : buffer.write(key, index, 'ascii');
  279. // Encode the name
  280. index = index + numberOfWrittenBytes;
  281. buffer[index++] = 0;
  282. // Get size of the buffer (current write point)
  283. const size = value.length;
  284. // Write the size of the string to buffer
  285. buffer[index++] = size & 0xff;
  286. buffer[index++] = (size >> 8) & 0xff;
  287. buffer[index++] = (size >> 16) & 0xff;
  288. buffer[index++] = (size >> 24) & 0xff;
  289. // Write the default subtype
  290. buffer[index++] = constants.BSON_BINARY_SUBTYPE_DEFAULT;
  291. // Copy the content form the binary field to the buffer
  292. value.copy(buffer, index, 0, size);
  293. // Adjust the index
  294. index = index + size;
  295. return index;
  296. }
  297. function serializeObject(
  298. buffer,
  299. key,
  300. value,
  301. index,
  302. checkKeys,
  303. depth,
  304. serializeFunctions,
  305. ignoreUndefined,
  306. isArray,
  307. path
  308. ) {
  309. for (let i = 0; i < path.length; i++) {
  310. if (path[i] === value) throw new Error('cyclic dependency detected');
  311. }
  312. // Push value to stack
  313. path.push(value);
  314. // Write the type
  315. buffer[index++] = Array.isArray(value) ? constants.BSON_DATA_ARRAY : constants.BSON_DATA_OBJECT;
  316. // Number of written bytes
  317. const numberOfWrittenBytes = !isArray
  318. ? buffer.write(key, index, 'utf8')
  319. : buffer.write(key, index, 'ascii');
  320. // Encode the name
  321. index = index + numberOfWrittenBytes;
  322. buffer[index++] = 0;
  323. const endIndex = serializeInto(
  324. buffer,
  325. value,
  326. checkKeys,
  327. index,
  328. depth + 1,
  329. serializeFunctions,
  330. ignoreUndefined,
  331. path
  332. );
  333. // Pop stack
  334. path.pop();
  335. return endIndex;
  336. }
  337. function serializeDecimal128(buffer, key, value, index, isArray) {
  338. buffer[index++] = constants.BSON_DATA_DECIMAL128;
  339. // Number of written bytes
  340. const numberOfWrittenBytes = !isArray
  341. ? buffer.write(key, index, 'utf8')
  342. : buffer.write(key, index, 'ascii');
  343. // Encode the name
  344. index = index + numberOfWrittenBytes;
  345. buffer[index++] = 0;
  346. // Write the data from the value
  347. value.bytes.copy(buffer, index, 0, 16);
  348. return index + 16;
  349. }
  350. function serializeLong(buffer, key, value, index, isArray) {
  351. // Write the type
  352. buffer[index++] =
  353. value._bsontype === 'Long' ? constants.BSON_DATA_LONG : constants.BSON_DATA_TIMESTAMP;
  354. // Number of written bytes
  355. const numberOfWrittenBytes = !isArray
  356. ? buffer.write(key, index, 'utf8')
  357. : buffer.write(key, index, 'ascii');
  358. // Encode the name
  359. index = index + numberOfWrittenBytes;
  360. buffer[index++] = 0;
  361. // Write the date
  362. const lowBits = value.getLowBits();
  363. const highBits = value.getHighBits();
  364. // Encode low bits
  365. buffer[index++] = lowBits & 0xff;
  366. buffer[index++] = (lowBits >> 8) & 0xff;
  367. buffer[index++] = (lowBits >> 16) & 0xff;
  368. buffer[index++] = (lowBits >> 24) & 0xff;
  369. // Encode high bits
  370. buffer[index++] = highBits & 0xff;
  371. buffer[index++] = (highBits >> 8) & 0xff;
  372. buffer[index++] = (highBits >> 16) & 0xff;
  373. buffer[index++] = (highBits >> 24) & 0xff;
  374. return index;
  375. }
  376. function serializeInt32(buffer, key, value, index, isArray) {
  377. // Set int type 32 bits or less
  378. buffer[index++] = constants.BSON_DATA_INT;
  379. // Number of written bytes
  380. const numberOfWrittenBytes = !isArray
  381. ? buffer.write(key, index, 'utf8')
  382. : buffer.write(key, index, 'ascii');
  383. // Encode the name
  384. index = index + numberOfWrittenBytes;
  385. buffer[index++] = 0;
  386. // Write the int value
  387. buffer[index++] = value & 0xff;
  388. buffer[index++] = (value >> 8) & 0xff;
  389. buffer[index++] = (value >> 16) & 0xff;
  390. buffer[index++] = (value >> 24) & 0xff;
  391. return index;
  392. }
  393. function serializeDouble(buffer, key, value, index, isArray) {
  394. // Encode as double
  395. buffer[index++] = constants.BSON_DATA_NUMBER;
  396. // Number of written bytes
  397. const numberOfWrittenBytes = !isArray
  398. ? buffer.write(key, index, 'utf8')
  399. : buffer.write(key, index, 'ascii');
  400. // Encode the name
  401. index = index + numberOfWrittenBytes;
  402. buffer[index++] = 0;
  403. // Write float
  404. writeIEEE754(buffer, value.value, index, 'little', 52, 8);
  405. // Adjust index
  406. index = index + 8;
  407. return index;
  408. }
  409. function serializeFunction(buffer, key, value, index, checkKeys, depth, isArray) {
  410. buffer[index++] = constants.BSON_DATA_CODE;
  411. // Number of written bytes
  412. const numberOfWrittenBytes = !isArray
  413. ? buffer.write(key, index, 'utf8')
  414. : buffer.write(key, index, 'ascii');
  415. // Encode the name
  416. index = index + numberOfWrittenBytes;
  417. buffer[index++] = 0;
  418. // Function string
  419. const functionString = normalizedFunctionString(value);
  420. // Write the string
  421. const size = buffer.write(functionString, index + 4, 'utf8') + 1;
  422. // Write the size of the string to buffer
  423. buffer[index] = size & 0xff;
  424. buffer[index + 1] = (size >> 8) & 0xff;
  425. buffer[index + 2] = (size >> 16) & 0xff;
  426. buffer[index + 3] = (size >> 24) & 0xff;
  427. // Update index
  428. index = index + 4 + size - 1;
  429. // Write zero
  430. buffer[index++] = 0;
  431. return index;
  432. }
  433. function serializeCode(
  434. buffer,
  435. key,
  436. value,
  437. index,
  438. checkKeys,
  439. depth,
  440. serializeFunctions,
  441. ignoreUndefined,
  442. isArray
  443. ) {
  444. if (value.scope && typeof value.scope === 'object') {
  445. // Write the type
  446. buffer[index++] = constants.BSON_DATA_CODE_W_SCOPE;
  447. // Number of written bytes
  448. const numberOfWrittenBytes = !isArray
  449. ? buffer.write(key, index, 'utf8')
  450. : buffer.write(key, index, 'ascii');
  451. // Encode the name
  452. index = index + numberOfWrittenBytes;
  453. buffer[index++] = 0;
  454. // Starting index
  455. let startIndex = index;
  456. // Serialize the function
  457. // Get the function string
  458. const functionString = typeof value.code === 'string' ? value.code : value.code.toString();
  459. // Index adjustment
  460. index = index + 4;
  461. // Write string into buffer
  462. const codeSize = buffer.write(functionString, index + 4, 'utf8') + 1;
  463. // Write the size of the string to buffer
  464. buffer[index] = codeSize & 0xff;
  465. buffer[index + 1] = (codeSize >> 8) & 0xff;
  466. buffer[index + 2] = (codeSize >> 16) & 0xff;
  467. buffer[index + 3] = (codeSize >> 24) & 0xff;
  468. // Write end 0
  469. buffer[index + 4 + codeSize - 1] = 0;
  470. // Write the
  471. index = index + codeSize + 4;
  472. //
  473. // Serialize the scope value
  474. const endIndex = serializeInto(
  475. buffer,
  476. value.scope,
  477. checkKeys,
  478. index,
  479. depth + 1,
  480. serializeFunctions,
  481. ignoreUndefined
  482. );
  483. index = endIndex - 1;
  484. // Writ the total
  485. const totalSize = endIndex - startIndex;
  486. // Write the total size of the object
  487. buffer[startIndex++] = totalSize & 0xff;
  488. buffer[startIndex++] = (totalSize >> 8) & 0xff;
  489. buffer[startIndex++] = (totalSize >> 16) & 0xff;
  490. buffer[startIndex++] = (totalSize >> 24) & 0xff;
  491. // Write trailing zero
  492. buffer[index++] = 0;
  493. } else {
  494. buffer[index++] = constants.BSON_DATA_CODE;
  495. // Number of written bytes
  496. const numberOfWrittenBytes = !isArray
  497. ? buffer.write(key, index, 'utf8')
  498. : buffer.write(key, index, 'ascii');
  499. // Encode the name
  500. index = index + numberOfWrittenBytes;
  501. buffer[index++] = 0;
  502. // Function string
  503. const functionString = value.code.toString();
  504. // Write the string
  505. const size = buffer.write(functionString, index + 4, 'utf8') + 1;
  506. // Write the size of the string to buffer
  507. buffer[index] = size & 0xff;
  508. buffer[index + 1] = (size >> 8) & 0xff;
  509. buffer[index + 2] = (size >> 16) & 0xff;
  510. buffer[index + 3] = (size >> 24) & 0xff;
  511. // Update index
  512. index = index + 4 + size - 1;
  513. // Write zero
  514. buffer[index++] = 0;
  515. }
  516. return index;
  517. }
  518. function serializeBinary(buffer, key, value, index, isArray) {
  519. // Write the type
  520. buffer[index++] = constants.BSON_DATA_BINARY;
  521. // Number of written bytes
  522. const numberOfWrittenBytes = !isArray
  523. ? buffer.write(key, index, 'utf8')
  524. : buffer.write(key, index, 'ascii');
  525. // Encode the name
  526. index = index + numberOfWrittenBytes;
  527. buffer[index++] = 0;
  528. // Extract the buffer
  529. const data = value.value(true);
  530. // Calculate size
  531. let size = value.position;
  532. // Add the deprecated 02 type 4 bytes of size to total
  533. if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) size = size + 4;
  534. // Write the size of the string to buffer
  535. buffer[index++] = size & 0xff;
  536. buffer[index++] = (size >> 8) & 0xff;
  537. buffer[index++] = (size >> 16) & 0xff;
  538. buffer[index++] = (size >> 24) & 0xff;
  539. // Write the subtype to the buffer
  540. buffer[index++] = value.sub_type;
  541. // If we have binary type 2 the 4 first bytes are the size
  542. if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
  543. size = size - 4;
  544. buffer[index++] = size & 0xff;
  545. buffer[index++] = (size >> 8) & 0xff;
  546. buffer[index++] = (size >> 16) & 0xff;
  547. buffer[index++] = (size >> 24) & 0xff;
  548. }
  549. // Write the data to the object
  550. data.copy(buffer, index, 0, value.position);
  551. // Adjust the index
  552. index = index + value.position;
  553. return index;
  554. }
  555. function serializeSymbol(buffer, key, value, index, isArray) {
  556. // Write the type
  557. buffer[index++] = constants.BSON_DATA_SYMBOL;
  558. // Number of written bytes
  559. const numberOfWrittenBytes = !isArray
  560. ? buffer.write(key, index, 'utf8')
  561. : buffer.write(key, index, 'ascii');
  562. // Encode the name
  563. index = index + numberOfWrittenBytes;
  564. buffer[index++] = 0;
  565. // Write the string
  566. const size = buffer.write(value.value, index + 4, 'utf8') + 1;
  567. // Write the size of the string to buffer
  568. buffer[index] = size & 0xff;
  569. buffer[index + 1] = (size >> 8) & 0xff;
  570. buffer[index + 2] = (size >> 16) & 0xff;
  571. buffer[index + 3] = (size >> 24) & 0xff;
  572. // Update index
  573. index = index + 4 + size - 1;
  574. // Write zero
  575. buffer[index++] = 0x00;
  576. return index;
  577. }
  578. function serializeDBRef(buffer, key, value, index, depth, serializeFunctions, isArray) {
  579. // Write the type
  580. buffer[index++] = constants.BSON_DATA_OBJECT;
  581. // Number of written bytes
  582. const numberOfWrittenBytes = !isArray
  583. ? buffer.write(key, index, 'utf8')
  584. : buffer.write(key, index, 'ascii');
  585. // Encode the name
  586. index = index + numberOfWrittenBytes;
  587. buffer[index++] = 0;
  588. let startIndex = index;
  589. let endIndex;
  590. let output = {
  591. $ref: value.collection,
  592. $id: value.oid
  593. };
  594. if (value.db != null) output.$db = value.db;
  595. output = Object.assign(output, value.fields);
  596. endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions);
  597. // Calculate object size
  598. const size = endIndex - startIndex;
  599. // Write the size
  600. buffer[startIndex++] = size & 0xff;
  601. buffer[startIndex++] = (size >> 8) & 0xff;
  602. buffer[startIndex++] = (size >> 16) & 0xff;
  603. buffer[startIndex++] = (size >> 24) & 0xff;
  604. // Set index
  605. return endIndex;
  606. }
  607. function serializeInto(
  608. buffer,
  609. object,
  610. checkKeys,
  611. startingIndex,
  612. depth,
  613. serializeFunctions,
  614. ignoreUndefined,
  615. path
  616. ) {
  617. startingIndex = startingIndex || 0;
  618. path = path || [];
  619. // Push the object to the path
  620. path.push(object);
  621. // Start place to serialize into
  622. let index = startingIndex + 4;
  623. // Special case isArray
  624. if (Array.isArray(object)) {
  625. // Get object keys
  626. for (let i = 0; i < object.length; i++) {
  627. let key = '' + i;
  628. let value = object[i];
  629. // Is there an override value
  630. if (value && value.toBSON) {
  631. if (typeof value.toBSON !== 'function') throw new TypeError('toBSON is not a function');
  632. value = value.toBSON();
  633. }
  634. const type = typeof value;
  635. if (type === 'string') {
  636. index = serializeString(buffer, key, value, index, true);
  637. } else if (type === 'number') {
  638. index = serializeNumber(buffer, key, value, index, true);
  639. } else if (type === 'boolean') {
  640. index = serializeBoolean(buffer, key, value, index, true);
  641. } else if (value instanceof Date || isDate(value)) {
  642. index = serializeDate(buffer, key, value, index, true);
  643. } else if (value === undefined) {
  644. index = serializeNull(buffer, key, value, index, true);
  645. } else if (value === null) {
  646. index = serializeNull(buffer, key, value, index, true);
  647. } else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
  648. index = serializeObjectId(buffer, key, value, index, true);
  649. } else if (Buffer.isBuffer(value)) {
  650. index = serializeBuffer(buffer, key, value, index, true);
  651. } else if (value instanceof RegExp || isRegExp(value)) {
  652. index = serializeRegExp(buffer, key, value, index, true);
  653. } else if (type === 'object' && value['_bsontype'] == null) {
  654. index = serializeObject(
  655. buffer,
  656. key,
  657. value,
  658. index,
  659. checkKeys,
  660. depth,
  661. serializeFunctions,
  662. ignoreUndefined,
  663. true,
  664. path
  665. );
  666. } else if (type === 'object' && value['_bsontype'] === 'Decimal128') {
  667. index = serializeDecimal128(buffer, key, value, index, true);
  668. } else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
  669. index = serializeLong(buffer, key, value, index, true);
  670. } else if (value['_bsontype'] === 'Double') {
  671. index = serializeDouble(buffer, key, value, index, true);
  672. } else if (typeof value === 'function' && serializeFunctions) {
  673. index = serializeFunction(
  674. buffer,
  675. key,
  676. value,
  677. index,
  678. checkKeys,
  679. depth,
  680. serializeFunctions,
  681. true
  682. );
  683. } else if (value['_bsontype'] === 'Code') {
  684. index = serializeCode(
  685. buffer,
  686. key,
  687. value,
  688. index,
  689. checkKeys,
  690. depth,
  691. serializeFunctions,
  692. ignoreUndefined,
  693. true
  694. );
  695. } else if (value['_bsontype'] === 'Binary') {
  696. index = serializeBinary(buffer, key, value, index, true);
  697. } else if (value['_bsontype'] === 'Symbol') {
  698. index = serializeSymbol(buffer, key, value, index, true);
  699. } else if (value['_bsontype'] === 'DBRef') {
  700. index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, true);
  701. } else if (value['_bsontype'] === 'BSONRegExp') {
  702. index = serializeBSONRegExp(buffer, key, value, index, true);
  703. } else if (value['_bsontype'] === 'Int32') {
  704. index = serializeInt32(buffer, key, value, index, true);
  705. } else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
  706. index = serializeMinMax(buffer, key, value, index, true);
  707. }
  708. }
  709. } else if (object instanceof Map) {
  710. const iterator = object.entries();
  711. let done = false;
  712. while (!done) {
  713. // Unpack the next entry
  714. const entry = iterator.next();
  715. done = entry.done;
  716. // Are we done, then skip and terminate
  717. if (done) continue;
  718. // Get the entry values
  719. const key = entry.value[0];
  720. const value = entry.value[1];
  721. // Check the type of the value
  722. const type = typeof value;
  723. // Check the key and throw error if it's illegal
  724. if (typeof key === 'string' && !ignoreKeys.has(key)) {
  725. if (key.match(regexp) != null) {
  726. // The BSON spec doesn't allow keys with null bytes because keys are
  727. // null-terminated.
  728. throw Error('key ' + key + ' must not contain null bytes');
  729. }
  730. if (checkKeys) {
  731. if ('$' === key[0]) {
  732. throw Error('key ' + key + " must not start with '$'");
  733. } else if (~key.indexOf('.')) {
  734. throw Error('key ' + key + " must not contain '.'");
  735. }
  736. }
  737. }
  738. if (type === 'string') {
  739. index = serializeString(buffer, key, value, index);
  740. } else if (type === 'number') {
  741. index = serializeNumber(buffer, key, value, index);
  742. } else if (type === 'boolean') {
  743. index = serializeBoolean(buffer, key, value, index);
  744. } else if (value instanceof Date || isDate(value)) {
  745. index = serializeDate(buffer, key, value, index);
  746. } else if (value === null || (value === undefined && ignoreUndefined === false)) {
  747. index = serializeNull(buffer, key, value, index);
  748. } else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
  749. index = serializeObjectId(buffer, key, value, index);
  750. } else if (Buffer.isBuffer(value)) {
  751. index = serializeBuffer(buffer, key, value, index);
  752. } else if (value instanceof RegExp || isRegExp(value)) {
  753. index = serializeRegExp(buffer, key, value, index);
  754. } else if (type === 'object' && value['_bsontype'] == null) {
  755. index = serializeObject(
  756. buffer,
  757. key,
  758. value,
  759. index,
  760. checkKeys,
  761. depth,
  762. serializeFunctions,
  763. ignoreUndefined,
  764. false,
  765. path
  766. );
  767. } else if (type === 'object' && value['_bsontype'] === 'Decimal128') {
  768. index = serializeDecimal128(buffer, key, value, index);
  769. } else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
  770. index = serializeLong(buffer, key, value, index);
  771. } else if (value['_bsontype'] === 'Double') {
  772. index = serializeDouble(buffer, key, value, index);
  773. } else if (value['_bsontype'] === 'Code') {
  774. index = serializeCode(
  775. buffer,
  776. key,
  777. value,
  778. index,
  779. checkKeys,
  780. depth,
  781. serializeFunctions,
  782. ignoreUndefined
  783. );
  784. } else if (typeof value === 'function' && serializeFunctions) {
  785. index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
  786. } else if (value['_bsontype'] === 'Binary') {
  787. index = serializeBinary(buffer, key, value, index);
  788. } else if (value['_bsontype'] === 'Symbol') {
  789. index = serializeSymbol(buffer, key, value, index);
  790. } else if (value['_bsontype'] === 'DBRef') {
  791. index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
  792. } else if (value['_bsontype'] === 'BSONRegExp') {
  793. index = serializeBSONRegExp(buffer, key, value, index);
  794. } else if (value['_bsontype'] === 'Int32') {
  795. index = serializeInt32(buffer, key, value, index);
  796. } else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
  797. index = serializeMinMax(buffer, key, value, index);
  798. }
  799. }
  800. } else {
  801. // Did we provide a custom serialization method
  802. if (object.toBSON) {
  803. if (typeof object.toBSON !== 'function') throw new TypeError('toBSON is not a function');
  804. object = object.toBSON();
  805. if (object != null && typeof object !== 'object')
  806. throw new TypeError('toBSON function did not return an object');
  807. }
  808. // Iterate over all the keys
  809. for (let key in object) {
  810. let value = object[key];
  811. // Is there an override value
  812. if (value && value.toBSON) {
  813. if (typeof value.toBSON !== 'function') throw new TypeError('toBSON is not a function');
  814. value = value.toBSON();
  815. }
  816. // Check the type of the value
  817. const type = typeof value;
  818. // Check the key and throw error if it's illegal
  819. if (typeof key === 'string' && !ignoreKeys.has(key)) {
  820. if (key.match(regexp) != null) {
  821. // The BSON spec doesn't allow keys with null bytes because keys are
  822. // null-terminated.
  823. throw Error('key ' + key + ' must not contain null bytes');
  824. }
  825. if (checkKeys) {
  826. if ('$' === key[0]) {
  827. throw Error('key ' + key + " must not start with '$'");
  828. } else if (~key.indexOf('.')) {
  829. throw Error('key ' + key + " must not contain '.'");
  830. }
  831. }
  832. }
  833. if (type === 'string') {
  834. index = serializeString(buffer, key, value, index);
  835. } else if (type === 'number') {
  836. index = serializeNumber(buffer, key, value, index);
  837. } else if (type === 'boolean') {
  838. index = serializeBoolean(buffer, key, value, index);
  839. } else if (value instanceof Date || isDate(value)) {
  840. index = serializeDate(buffer, key, value, index);
  841. } else if (value === undefined) {
  842. if (ignoreUndefined === false) index = serializeNull(buffer, key, value, index);
  843. } else if (value === null) {
  844. index = serializeNull(buffer, key, value, index);
  845. } else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
  846. index = serializeObjectId(buffer, key, value, index);
  847. } else if (Buffer.isBuffer(value)) {
  848. index = serializeBuffer(buffer, key, value, index);
  849. } else if (value instanceof RegExp || isRegExp(value)) {
  850. index = serializeRegExp(buffer, key, value, index);
  851. } else if (type === 'object' && value['_bsontype'] == null) {
  852. index = serializeObject(
  853. buffer,
  854. key,
  855. value,
  856. index,
  857. checkKeys,
  858. depth,
  859. serializeFunctions,
  860. ignoreUndefined,
  861. false,
  862. path
  863. );
  864. } else if (type === 'object' && value['_bsontype'] === 'Decimal128') {
  865. index = serializeDecimal128(buffer, key, value, index);
  866. } else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
  867. index = serializeLong(buffer, key, value, index);
  868. } else if (value['_bsontype'] === 'Double') {
  869. index = serializeDouble(buffer, key, value, index);
  870. } else if (value['_bsontype'] === 'Code') {
  871. index = serializeCode(
  872. buffer,
  873. key,
  874. value,
  875. index,
  876. checkKeys,
  877. depth,
  878. serializeFunctions,
  879. ignoreUndefined
  880. );
  881. } else if (typeof value === 'function' && serializeFunctions) {
  882. index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
  883. } else if (value['_bsontype'] === 'Binary') {
  884. index = serializeBinary(buffer, key, value, index);
  885. } else if (value['_bsontype'] === 'Symbol') {
  886. index = serializeSymbol(buffer, key, value, index);
  887. } else if (value['_bsontype'] === 'DBRef') {
  888. index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
  889. } else if (value['_bsontype'] === 'BSONRegExp') {
  890. index = serializeBSONRegExp(buffer, key, value, index);
  891. } else if (value['_bsontype'] === 'Int32') {
  892. index = serializeInt32(buffer, key, value, index);
  893. } else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
  894. index = serializeMinMax(buffer, key, value, index);
  895. }
  896. }
  897. }
  898. // Remove the path
  899. path.pop();
  900. // Final padding byte for object
  901. buffer[index++] = 0x00;
  902. // Final size
  903. const size = index - startingIndex;
  904. // Write the size of the object
  905. buffer[startingIndex++] = size & 0xff;
  906. buffer[startingIndex++] = (size >> 8) & 0xff;
  907. buffer[startingIndex++] = (size >> 16) & 0xff;
  908. buffer[startingIndex++] = (size >> 24) & 0xff;
  909. return index;
  910. }
  911. module.exports = serializeInto;