BsonEncoder.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.BsonEncoder = void 0;
  4. const values_1 = require("./values");
  5. class BsonEncoder {
  6. constructor(writer) {
  7. this.writer = writer;
  8. }
  9. encode(value) {
  10. const writer = this.writer;
  11. writer.reset();
  12. this.writeAny(value);
  13. return writer.flush();
  14. }
  15. writeAny(value) {
  16. switch (typeof value) {
  17. case 'object': {
  18. if (value === null)
  19. throw new Error('NOT_OBJ');
  20. return this.writeObj(value);
  21. }
  22. }
  23. throw new Error('NOT_OBJ');
  24. }
  25. writeNull() {
  26. throw new Error('Method not implemented.');
  27. }
  28. writeUndef() {
  29. throw new Error('Method not implemented.');
  30. }
  31. writeBoolean(bool) {
  32. throw new Error('Method not implemented.');
  33. }
  34. writeNumber(num) {
  35. throw new Error('Method not implemented.');
  36. }
  37. writeInteger(int) {
  38. throw new Error('Method not implemented.');
  39. }
  40. writeUInteger(uint) {
  41. throw new Error('Method not implemented.');
  42. }
  43. writeInt32(int) {
  44. const writer = this.writer;
  45. writer.ensureCapacity(4);
  46. writer.view.setInt32(writer.x, int, true);
  47. writer.x += 4;
  48. }
  49. writeInt64(int) {
  50. const writer = this.writer;
  51. writer.ensureCapacity(8);
  52. writer.view.setBigInt64(writer.x, BigInt(int), true);
  53. writer.x += 8;
  54. }
  55. writeFloat(float) {
  56. const writer = this.writer;
  57. writer.ensureCapacity(4);
  58. writer.view.setFloat64(writer.x, float, true);
  59. writer.x += 8;
  60. }
  61. writeBigInt(int) {
  62. throw new Error('Method not implemented.');
  63. }
  64. writeBin(buf) {
  65. const length = buf.length;
  66. this.writeInt32(length);
  67. const writer = this.writer;
  68. writer.u8(0);
  69. writer.buf(buf, length);
  70. }
  71. writeStr(str) {
  72. const writer = this.writer;
  73. const length = str.length;
  74. const maxSize = 4 + 1 + 4 * length;
  75. writer.ensureCapacity(maxSize);
  76. const x = writer.x;
  77. this.writeInt32(length + 1);
  78. const bytesWritten = writer.utf8(str);
  79. writer.u8(0);
  80. if (bytesWritten !== length) {
  81. writer.view.setInt32(x, bytesWritten + 1, true);
  82. }
  83. }
  84. writeAsciiStr(str) {
  85. throw new Error('Method not implemented.');
  86. }
  87. writeArr(arr) {
  88. this.writeObj(arr);
  89. }
  90. writeObj(obj) {
  91. const writer = this.writer;
  92. writer.ensureCapacity(8);
  93. const x0 = writer.x0;
  94. const dx = writer.x - x0;
  95. writer.x += 4;
  96. const keys = Object.keys(obj);
  97. const length = keys.length;
  98. for (let i = 0; i < length; i++) {
  99. const key = keys[i];
  100. const value = obj[key];
  101. this.writeKey(key, value);
  102. }
  103. writer.u8(0);
  104. const x = writer.x0 + dx;
  105. const size = writer.x - x;
  106. writer.view.setUint32(x, size, true);
  107. }
  108. writeCString(str) {
  109. const writer = this.writer;
  110. const length = str.length;
  111. writer.ensureCapacity(1 + 4 * length);
  112. const uint8 = writer.uint8;
  113. let x = writer.x;
  114. let pos = 0;
  115. while (pos < length) {
  116. let value = str.charCodeAt(pos++);
  117. if ((value & 0xffffff80) === 0) {
  118. if (!value)
  119. break;
  120. uint8[x++] = value;
  121. continue;
  122. }
  123. else if ((value & 0xfffff800) === 0) {
  124. const octet = ((value >> 6) & 0x1f) | 0xc0;
  125. if (!octet)
  126. break;
  127. uint8[x++] = octet;
  128. }
  129. else {
  130. if (value >= 0xd800 && value <= 0xdbff) {
  131. if (pos < length) {
  132. const extra = str.charCodeAt(pos);
  133. if ((extra & 0xfc00) === 0xdc00) {
  134. pos++;
  135. value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
  136. }
  137. }
  138. }
  139. if ((value & 0xffff0000) === 0) {
  140. const octet1 = ((value >> 12) & 0x0f) | 0xe0;
  141. const octet2 = ((value >> 6) & 0x3f) | 0x80;
  142. if (!octet1 || !octet2)
  143. throw new Error('INVALID_CSTRING');
  144. uint8[x++] = octet1;
  145. uint8[x++] = octet2;
  146. }
  147. else {
  148. const octet1 = ((value >> 18) & 0x07) | 0xf0;
  149. const octet2 = ((value >> 12) & 0x3f) | 0x80;
  150. const octet3 = ((value >> 6) & 0x3f) | 0x80;
  151. if (!octet1 || !octet2 || !octet3)
  152. throw new Error('INVALID_CSTRING');
  153. uint8[x++] = octet1;
  154. uint8[x++] = octet2;
  155. uint8[x++] = octet3;
  156. }
  157. }
  158. const octet = (value & 0x3f) | 0x80;
  159. if (!octet)
  160. break;
  161. uint8[x++] = octet;
  162. }
  163. uint8[x++] = 0;
  164. writer.x = x;
  165. }
  166. writeObjectId(id) {
  167. const writer = this.writer;
  168. writer.ensureCapacity(12);
  169. const uint8 = writer.uint8;
  170. const x = writer.x;
  171. const { timestamp, process, counter } = id;
  172. uint8[x + 0] = timestamp >>> 24;
  173. uint8[x + 1] = (timestamp >>> 16) & 0xff;
  174. uint8[x + 2] = (timestamp >>> 8) & 0xff;
  175. uint8[x + 3] = timestamp & 0xff;
  176. uint8[x + 4] = process & 0xff;
  177. uint8[x + 5] = (process >>> 8) & 0xff;
  178. uint8[x + 6] = (process >>> 16) & 0xff;
  179. uint8[x + 7] = (process >>> 24) & 0xff;
  180. let lo32 = process | 0;
  181. if (lo32 < 0)
  182. lo32 += 4294967296;
  183. const hi32 = (process - lo32) / 4294967296;
  184. uint8[x + 8] = hi32 & 0xff;
  185. uint8[x + 9] = counter >>> 16;
  186. uint8[x + 10] = (counter >>> 8) & 0xff;
  187. uint8[x + 11] = counter & 0xff;
  188. writer.x += 12;
  189. }
  190. writeKey(key, value) {
  191. const writer = this.writer;
  192. switch (typeof value) {
  193. case 'number': {
  194. const isFloat = Math.floor(value) !== value;
  195. if (isFloat) {
  196. writer.u8(0x01);
  197. this.writeCString(key);
  198. this.writeFloat(value);
  199. break;
  200. }
  201. if (value <= 2147483647 && value >= -2147483648) {
  202. writer.u8(0x10);
  203. this.writeCString(key);
  204. this.writeInt32(value);
  205. break;
  206. }
  207. writer.u8(0x12);
  208. this.writeCString(key);
  209. this.writeInt64(value);
  210. break;
  211. }
  212. case 'string': {
  213. writer.u8(0x02);
  214. this.writeCString(key);
  215. this.writeStr(value);
  216. break;
  217. }
  218. case 'object': {
  219. if (value === null) {
  220. writer.u8(0x0a);
  221. this.writeCString(key);
  222. break;
  223. }
  224. const constructor = value.constructor;
  225. switch (constructor) {
  226. case Object: {
  227. writer.u8(0x03);
  228. this.writeCString(key);
  229. this.writeObj(value);
  230. break;
  231. }
  232. case Array: {
  233. writer.u8(0x04);
  234. this.writeCString(key);
  235. this.writeObj(value);
  236. break;
  237. }
  238. case Uint8Array: {
  239. writer.u8(0x05);
  240. this.writeCString(key);
  241. this.writeBin(value);
  242. break;
  243. }
  244. case values_1.BsonObjectId: {
  245. writer.u8(0x07);
  246. this.writeCString(key);
  247. this.writeObjectId(value);
  248. break;
  249. }
  250. case Date: {
  251. writer.u8(0x09);
  252. this.writeCString(key);
  253. writer.ensureCapacity(8);
  254. writer.view.setBigUint64(writer.x, BigInt(value.getTime()), true);
  255. writer.x += 8;
  256. break;
  257. }
  258. case RegExp: {
  259. writer.u8(0x0b);
  260. this.writeCString(key);
  261. this.writeCString(value.source);
  262. this.writeCString(value.flags);
  263. break;
  264. }
  265. case values_1.BsonDbPointer: {
  266. writer.u8(0x0c);
  267. this.writeCString(key);
  268. const pointer = value;
  269. this.writeStr(pointer.name);
  270. this.writeObjectId(pointer.id);
  271. break;
  272. }
  273. case values_1.BsonJavascriptCode: {
  274. writer.u8(0x0d);
  275. this.writeCString(key);
  276. this.writeStr(value.code);
  277. break;
  278. }
  279. case values_1.BsonInt32: {
  280. writer.u8(0x10);
  281. this.writeCString(key);
  282. this.writeInt32(value.value);
  283. break;
  284. }
  285. case values_1.BsonInt64: {
  286. writer.u8(0x12);
  287. this.writeCString(key);
  288. this.writeInt64(value.value);
  289. break;
  290. }
  291. case values_1.BsonFloat: {
  292. writer.u8(0x01);
  293. this.writeCString(key);
  294. this.writeFloat(value.value);
  295. break;
  296. }
  297. case values_1.BsonTimestamp: {
  298. writer.u8(0x11);
  299. this.writeCString(key);
  300. const ts = value;
  301. this.writeInt32(ts.increment);
  302. this.writeInt32(ts.timestamp);
  303. break;
  304. }
  305. case values_1.BsonDecimal128: {
  306. writer.u8(0x13);
  307. this.writeCString(key);
  308. const dec = value;
  309. if (dec.data.length !== 16)
  310. throw new Error('INVALID_DECIMAL128');
  311. writer.buf(dec.data, 16);
  312. break;
  313. }
  314. case values_1.BsonMinKey: {
  315. writer.u8(0xff);
  316. this.writeCString(key);
  317. break;
  318. }
  319. case values_1.BsonMaxKey: {
  320. writer.u8(0x7f);
  321. this.writeCString(key);
  322. break;
  323. }
  324. case values_1.BsonBinary: {
  325. writer.u8(0x05);
  326. this.writeCString(key);
  327. const bin = value;
  328. const length = bin.data.length;
  329. this.writeInt32(length);
  330. writer.u8(bin.subtype);
  331. writer.buf(bin.data, length);
  332. break;
  333. }
  334. default: {
  335. writer.u8(0x03);
  336. this.writeCString(key);
  337. this.writeObj(value);
  338. break;
  339. }
  340. }
  341. break;
  342. }
  343. case 'boolean': {
  344. writer.u8(0x08);
  345. this.writeCString(key);
  346. writer.u8(+value);
  347. break;
  348. }
  349. case 'undefined': {
  350. writer.u8(0x06);
  351. this.writeCString(key);
  352. break;
  353. }
  354. case 'symbol': {
  355. writer.u8(0x0e);
  356. this.writeCString(key);
  357. this.writeStr(value.description || '');
  358. break;
  359. }
  360. }
  361. }
  362. }
  363. exports.BsonEncoder = BsonEncoder;
  364. //# sourceMappingURL=BsonEncoder.js.map