binary.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. "use strict";
  2. var __extends = (this && this.__extends) || (function () {
  3. var extendStatics = function (d, b) {
  4. extendStatics = Object.setPrototypeOf ||
  5. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  6. function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
  7. return extendStatics(d, b);
  8. };
  9. return function (d, b) {
  10. if (typeof b !== "function" && b !== null)
  11. throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
  12. extendStatics(d, b);
  13. function __() { this.constructor = d; }
  14. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  15. };
  16. })();
  17. Object.defineProperty(exports, "__esModule", { value: true });
  18. exports.UUID = exports.Binary = void 0;
  19. var buffer_1 = require("buffer");
  20. var ensure_buffer_1 = require("./ensure_buffer");
  21. var uuid_utils_1 = require("./uuid_utils");
  22. var utils_1 = require("./parser/utils");
  23. var error_1 = require("./error");
  24. var constants_1 = require("./constants");
  25. /**
  26. * A class representation of the BSON Binary type.
  27. * @public
  28. * @category BSONType
  29. */
  30. var Binary = /** @class */ (function () {
  31. /**
  32. * Create a new Binary instance.
  33. *
  34. * This constructor can accept a string as its first argument. In this case,
  35. * this string will be encoded using ISO-8859-1, **not** using UTF-8.
  36. * This is almost certainly not what you want. Use `new Binary(Buffer.from(string))`
  37. * instead to convert the string to a Buffer using UTF-8 first.
  38. *
  39. * @param buffer - a buffer object containing the binary data.
  40. * @param subType - the option binary type.
  41. */
  42. function Binary(buffer, subType) {
  43. if (!(this instanceof Binary))
  44. return new Binary(buffer, subType);
  45. if (!(buffer == null) &&
  46. !(typeof buffer === 'string') &&
  47. !ArrayBuffer.isView(buffer) &&
  48. !(buffer instanceof ArrayBuffer) &&
  49. !Array.isArray(buffer)) {
  50. throw new error_1.BSONTypeError('Binary can only be constructed from string, Buffer, TypedArray, or Array<number>');
  51. }
  52. this.sub_type = subType !== null && subType !== void 0 ? subType : Binary.BSON_BINARY_SUBTYPE_DEFAULT;
  53. if (buffer == null) {
  54. // create an empty binary buffer
  55. this.buffer = buffer_1.Buffer.alloc(Binary.BUFFER_SIZE);
  56. this.position = 0;
  57. }
  58. else {
  59. if (typeof buffer === 'string') {
  60. // string
  61. this.buffer = buffer_1.Buffer.from(buffer, 'binary');
  62. }
  63. else if (Array.isArray(buffer)) {
  64. // number[]
  65. this.buffer = buffer_1.Buffer.from(buffer);
  66. }
  67. else {
  68. // Buffer | TypedArray | ArrayBuffer
  69. this.buffer = (0, ensure_buffer_1.ensureBuffer)(buffer);
  70. }
  71. this.position = this.buffer.byteLength;
  72. }
  73. }
  74. /**
  75. * Updates this binary with byte_value.
  76. *
  77. * @param byteValue - a single byte we wish to write.
  78. */
  79. Binary.prototype.put = function (byteValue) {
  80. // If it's a string and a has more than one character throw an error
  81. if (typeof byteValue === 'string' && byteValue.length !== 1) {
  82. throw new error_1.BSONTypeError('only accepts single character String');
  83. }
  84. else if (typeof byteValue !== 'number' && byteValue.length !== 1)
  85. throw new error_1.BSONTypeError('only accepts single character Uint8Array or Array');
  86. // Decode the byte value once
  87. var decodedByte;
  88. if (typeof byteValue === 'string') {
  89. decodedByte = byteValue.charCodeAt(0);
  90. }
  91. else if (typeof byteValue === 'number') {
  92. decodedByte = byteValue;
  93. }
  94. else {
  95. decodedByte = byteValue[0];
  96. }
  97. if (decodedByte < 0 || decodedByte > 255) {
  98. throw new error_1.BSONTypeError('only accepts number in a valid unsigned byte range 0-255');
  99. }
  100. if (this.buffer.length > this.position) {
  101. this.buffer[this.position++] = decodedByte;
  102. }
  103. else {
  104. var buffer = buffer_1.Buffer.alloc(Binary.BUFFER_SIZE + this.buffer.length);
  105. // Combine the two buffers together
  106. this.buffer.copy(buffer, 0, 0, this.buffer.length);
  107. this.buffer = buffer;
  108. this.buffer[this.position++] = decodedByte;
  109. }
  110. };
  111. /**
  112. * Writes a buffer or string to the binary.
  113. *
  114. * @param sequence - a string or buffer to be written to the Binary BSON object.
  115. * @param offset - specify the binary of where to write the content.
  116. */
  117. Binary.prototype.write = function (sequence, offset) {
  118. offset = typeof offset === 'number' ? offset : this.position;
  119. // If the buffer is to small let's extend the buffer
  120. if (this.buffer.length < offset + sequence.length) {
  121. var buffer = buffer_1.Buffer.alloc(this.buffer.length + sequence.length);
  122. this.buffer.copy(buffer, 0, 0, this.buffer.length);
  123. // Assign the new buffer
  124. this.buffer = buffer;
  125. }
  126. if (ArrayBuffer.isView(sequence)) {
  127. this.buffer.set((0, ensure_buffer_1.ensureBuffer)(sequence), offset);
  128. this.position =
  129. offset + sequence.byteLength > this.position ? offset + sequence.length : this.position;
  130. }
  131. else if (typeof sequence === 'string') {
  132. this.buffer.write(sequence, offset, sequence.length, 'binary');
  133. this.position =
  134. offset + sequence.length > this.position ? offset + sequence.length : this.position;
  135. }
  136. };
  137. /**
  138. * Reads **length** bytes starting at **position**.
  139. *
  140. * @param position - read from the given position in the Binary.
  141. * @param length - the number of bytes to read.
  142. */
  143. Binary.prototype.read = function (position, length) {
  144. length = length && length > 0 ? length : this.position;
  145. // Let's return the data based on the type we have
  146. return this.buffer.slice(position, position + length);
  147. };
  148. /**
  149. * Returns the value of this binary as a string.
  150. * @param asRaw - Will skip converting to a string
  151. * @remarks
  152. * This is handy when calling this function conditionally for some key value pairs and not others
  153. */
  154. Binary.prototype.value = function (asRaw) {
  155. asRaw = !!asRaw;
  156. // Optimize to serialize for the situation where the data == size of buffer
  157. if (asRaw && this.buffer.length === this.position) {
  158. return this.buffer;
  159. }
  160. // If it's a node.js buffer object
  161. if (asRaw) {
  162. return this.buffer.slice(0, this.position);
  163. }
  164. return this.buffer.toString('binary', 0, this.position);
  165. };
  166. /** the length of the binary sequence */
  167. Binary.prototype.length = function () {
  168. return this.position;
  169. };
  170. Binary.prototype.toJSON = function () {
  171. return this.buffer.toString('base64');
  172. };
  173. Binary.prototype.toString = function (format) {
  174. return this.buffer.toString(format);
  175. };
  176. /** @internal */
  177. Binary.prototype.toExtendedJSON = function (options) {
  178. options = options || {};
  179. var base64String = this.buffer.toString('base64');
  180. var subType = Number(this.sub_type).toString(16);
  181. if (options.legacy) {
  182. return {
  183. $binary: base64String,
  184. $type: subType.length === 1 ? '0' + subType : subType
  185. };
  186. }
  187. return {
  188. $binary: {
  189. base64: base64String,
  190. subType: subType.length === 1 ? '0' + subType : subType
  191. }
  192. };
  193. };
  194. Binary.prototype.toUUID = function () {
  195. if (this.sub_type === Binary.SUBTYPE_UUID) {
  196. return new UUID(this.buffer.slice(0, this.position));
  197. }
  198. throw new error_1.BSONError("Binary sub_type \"".concat(this.sub_type, "\" is not supported for converting to UUID. Only \"").concat(Binary.SUBTYPE_UUID, "\" is currently supported."));
  199. };
  200. /** @internal */
  201. Binary.fromExtendedJSON = function (doc, options) {
  202. options = options || {};
  203. var data;
  204. var type;
  205. if ('$binary' in doc) {
  206. if (options.legacy && typeof doc.$binary === 'string' && '$type' in doc) {
  207. type = doc.$type ? parseInt(doc.$type, 16) : 0;
  208. data = buffer_1.Buffer.from(doc.$binary, 'base64');
  209. }
  210. else {
  211. if (typeof doc.$binary !== 'string') {
  212. type = doc.$binary.subType ? parseInt(doc.$binary.subType, 16) : 0;
  213. data = buffer_1.Buffer.from(doc.$binary.base64, 'base64');
  214. }
  215. }
  216. }
  217. else if ('$uuid' in doc) {
  218. type = 4;
  219. data = (0, uuid_utils_1.uuidHexStringToBuffer)(doc.$uuid);
  220. }
  221. if (!data) {
  222. throw new error_1.BSONTypeError("Unexpected Binary Extended JSON format ".concat(JSON.stringify(doc)));
  223. }
  224. return type === constants_1.BSON_BINARY_SUBTYPE_UUID_NEW ? new UUID(data) : new Binary(data, type);
  225. };
  226. /** @internal */
  227. Binary.prototype[Symbol.for('nodejs.util.inspect.custom')] = function () {
  228. return this.inspect();
  229. };
  230. Binary.prototype.inspect = function () {
  231. var asBuffer = this.value(true);
  232. return "new Binary(Buffer.from(\"".concat(asBuffer.toString('hex'), "\", \"hex\"), ").concat(this.sub_type, ")");
  233. };
  234. /**
  235. * Binary default subtype
  236. * @internal
  237. */
  238. Binary.BSON_BINARY_SUBTYPE_DEFAULT = 0;
  239. /** Initial buffer default size */
  240. Binary.BUFFER_SIZE = 256;
  241. /** Default BSON type */
  242. Binary.SUBTYPE_DEFAULT = 0;
  243. /** Function BSON type */
  244. Binary.SUBTYPE_FUNCTION = 1;
  245. /** Byte Array BSON type */
  246. Binary.SUBTYPE_BYTE_ARRAY = 2;
  247. /** Deprecated UUID BSON type @deprecated Please use SUBTYPE_UUID */
  248. Binary.SUBTYPE_UUID_OLD = 3;
  249. /** UUID BSON type */
  250. Binary.SUBTYPE_UUID = 4;
  251. /** MD5 BSON type */
  252. Binary.SUBTYPE_MD5 = 5;
  253. /** Encrypted BSON type */
  254. Binary.SUBTYPE_ENCRYPTED = 6;
  255. /** Column BSON type */
  256. Binary.SUBTYPE_COLUMN = 7;
  257. /** User BSON type */
  258. Binary.SUBTYPE_USER_DEFINED = 128;
  259. return Binary;
  260. }());
  261. exports.Binary = Binary;
  262. Object.defineProperty(Binary.prototype, '_bsontype', { value: 'Binary' });
  263. var UUID_BYTE_LENGTH = 16;
  264. /**
  265. * A class representation of the BSON UUID type.
  266. * @public
  267. */
  268. var UUID = /** @class */ (function (_super) {
  269. __extends(UUID, _super);
  270. /**
  271. * Create an UUID type
  272. *
  273. * @param input - Can be a 32 or 36 character hex string (dashes excluded/included) or a 16 byte binary Buffer.
  274. */
  275. function UUID(input) {
  276. var _this = this;
  277. var bytes;
  278. var hexStr;
  279. if (input == null) {
  280. bytes = UUID.generate();
  281. }
  282. else if (input instanceof UUID) {
  283. bytes = buffer_1.Buffer.from(input.buffer);
  284. hexStr = input.__id;
  285. }
  286. else if (ArrayBuffer.isView(input) && input.byteLength === UUID_BYTE_LENGTH) {
  287. bytes = (0, ensure_buffer_1.ensureBuffer)(input);
  288. }
  289. else if (typeof input === 'string') {
  290. bytes = (0, uuid_utils_1.uuidHexStringToBuffer)(input);
  291. }
  292. else {
  293. throw new error_1.BSONTypeError('Argument passed in UUID constructor must be a UUID, a 16 byte Buffer or a 32/36 character hex string (dashes excluded/included, format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).');
  294. }
  295. _this = _super.call(this, bytes, constants_1.BSON_BINARY_SUBTYPE_UUID_NEW) || this;
  296. _this.__id = hexStr;
  297. return _this;
  298. }
  299. Object.defineProperty(UUID.prototype, "id", {
  300. /**
  301. * The UUID bytes
  302. * @readonly
  303. */
  304. get: function () {
  305. return this.buffer;
  306. },
  307. set: function (value) {
  308. this.buffer = value;
  309. if (UUID.cacheHexString) {
  310. this.__id = (0, uuid_utils_1.bufferToUuidHexString)(value);
  311. }
  312. },
  313. enumerable: false,
  314. configurable: true
  315. });
  316. /**
  317. * Returns the UUID id as a 32 or 36 character hex string representation, excluding/including dashes (defaults to 36 character dash separated)
  318. * @param includeDashes - should the string exclude dash-separators.
  319. * */
  320. UUID.prototype.toHexString = function (includeDashes) {
  321. if (includeDashes === void 0) { includeDashes = true; }
  322. if (UUID.cacheHexString && this.__id) {
  323. return this.__id;
  324. }
  325. var uuidHexString = (0, uuid_utils_1.bufferToUuidHexString)(this.id, includeDashes);
  326. if (UUID.cacheHexString) {
  327. this.__id = uuidHexString;
  328. }
  329. return uuidHexString;
  330. };
  331. /**
  332. * Converts the id into a 36 character (dashes included) hex string, unless a encoding is specified.
  333. */
  334. UUID.prototype.toString = function (encoding) {
  335. return encoding ? this.id.toString(encoding) : this.toHexString();
  336. };
  337. /**
  338. * Converts the id into its JSON string representation.
  339. * A 36 character (dashes included) hex string in the format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  340. */
  341. UUID.prototype.toJSON = function () {
  342. return this.toHexString();
  343. };
  344. /**
  345. * Compares the equality of this UUID with `otherID`.
  346. *
  347. * @param otherId - UUID instance to compare against.
  348. */
  349. UUID.prototype.equals = function (otherId) {
  350. if (!otherId) {
  351. return false;
  352. }
  353. if (otherId instanceof UUID) {
  354. return otherId.id.equals(this.id);
  355. }
  356. try {
  357. return new UUID(otherId).id.equals(this.id);
  358. }
  359. catch (_a) {
  360. return false;
  361. }
  362. };
  363. /**
  364. * Creates a Binary instance from the current UUID.
  365. */
  366. UUID.prototype.toBinary = function () {
  367. return new Binary(this.id, Binary.SUBTYPE_UUID);
  368. };
  369. /**
  370. * Generates a populated buffer containing a v4 uuid
  371. */
  372. UUID.generate = function () {
  373. var bytes = (0, utils_1.randomBytes)(UUID_BYTE_LENGTH);
  374. // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
  375. // Kindly borrowed from https://github.com/uuidjs/uuid/blob/master/src/v4.js
  376. bytes[6] = (bytes[6] & 0x0f) | 0x40;
  377. bytes[8] = (bytes[8] & 0x3f) | 0x80;
  378. return buffer_1.Buffer.from(bytes);
  379. };
  380. /**
  381. * Checks if a value is a valid bson UUID
  382. * @param input - UUID, string or Buffer to validate.
  383. */
  384. UUID.isValid = function (input) {
  385. if (!input) {
  386. return false;
  387. }
  388. if (input instanceof UUID) {
  389. return true;
  390. }
  391. if (typeof input === 'string') {
  392. return (0, uuid_utils_1.uuidValidateString)(input);
  393. }
  394. if ((0, utils_1.isUint8Array)(input)) {
  395. // check for length & uuid version (https://tools.ietf.org/html/rfc4122#section-4.1.3)
  396. if (input.length !== UUID_BYTE_LENGTH) {
  397. return false;
  398. }
  399. return (input[6] & 0xf0) === 0x40 && (input[8] & 0x80) === 0x80;
  400. }
  401. return false;
  402. };
  403. /**
  404. * Creates an UUID from a hex string representation of an UUID.
  405. * @param hexString - 32 or 36 character hex string (dashes excluded/included).
  406. */
  407. UUID.createFromHexString = function (hexString) {
  408. var buffer = (0, uuid_utils_1.uuidHexStringToBuffer)(hexString);
  409. return new UUID(buffer);
  410. };
  411. /**
  412. * Converts to a string representation of this Id.
  413. *
  414. * @returns return the 36 character hex string representation.
  415. * @internal
  416. */
  417. UUID.prototype[Symbol.for('nodejs.util.inspect.custom')] = function () {
  418. return this.inspect();
  419. };
  420. UUID.prototype.inspect = function () {
  421. return "new UUID(\"".concat(this.toHexString(), "\")");
  422. };
  423. return UUID;
  424. }(Binary));
  425. exports.UUID = UUID;
  426. //# sourceMappingURL=binary.js.map