BsonDecoder.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.BsonDecoder = void 0;
  4. const Reader_1 = require("@jsonjoy.com/buffers/lib/Reader");
  5. const values_1 = require("./values");
  6. class BsonDecoder {
  7. constructor(reader = new Reader_1.Reader()) {
  8. this.reader = reader;
  9. }
  10. read(uint8) {
  11. this.reader.reset(uint8);
  12. return this.readDocument();
  13. }
  14. decode(uint8) {
  15. this.reader.reset(uint8);
  16. return this.readDocument();
  17. }
  18. readAny() {
  19. return this.readDocument();
  20. }
  21. readDocument() {
  22. const reader = this.reader;
  23. const documentSize = reader.view.getInt32(reader.x, true);
  24. reader.x += 4;
  25. const startPos = reader.x;
  26. const endPos = startPos + documentSize - 4 - 1;
  27. const obj = {};
  28. while (reader.x < endPos) {
  29. const elementType = reader.u8();
  30. if (elementType === 0)
  31. break;
  32. const key = this.readCString();
  33. const value = this.readElementValue(elementType);
  34. obj[key] = value;
  35. }
  36. if (reader.x <= endPos) {
  37. reader.x = startPos + documentSize - 4;
  38. }
  39. return obj;
  40. }
  41. readCString() {
  42. const reader = this.reader;
  43. const uint8 = reader.uint8;
  44. const x = reader.x;
  45. let length = 0;
  46. while (uint8[x + length] !== 0) {
  47. length++;
  48. }
  49. if (length === 0) {
  50. reader.x++;
  51. return '';
  52. }
  53. const str = reader.utf8(length);
  54. reader.x++;
  55. return str;
  56. }
  57. readString() {
  58. const reader = this.reader;
  59. const length = reader.view.getInt32(reader.x, true);
  60. reader.x += 4;
  61. if (length <= 0) {
  62. throw new Error('Invalid string length');
  63. }
  64. const str = reader.utf8(length - 1);
  65. reader.x++;
  66. return str;
  67. }
  68. readElementValue(type) {
  69. const reader = this.reader;
  70. switch (type) {
  71. case 0x01:
  72. const doubleVal = reader.view.getFloat64(reader.x, true);
  73. reader.x += 8;
  74. return doubleVal;
  75. case 0x02:
  76. return this.readString();
  77. case 0x03:
  78. return this.readDocument();
  79. case 0x04:
  80. return this.readArray();
  81. case 0x05:
  82. return this.readBinary();
  83. case 0x06:
  84. return undefined;
  85. case 0x07:
  86. return this.readObjectId();
  87. case 0x08:
  88. return reader.u8() === 1;
  89. case 0x09:
  90. const dateVal = reader.view.getBigInt64(reader.x, true);
  91. reader.x += 8;
  92. return new Date(Number(dateVal));
  93. case 0x0a:
  94. return null;
  95. case 0x0b:
  96. return this.readRegex();
  97. case 0x0c:
  98. return this.readDbPointer();
  99. case 0x0d:
  100. return new values_1.BsonJavascriptCode(this.readString());
  101. case 0x0e:
  102. return Symbol(this.readString());
  103. case 0x0f:
  104. return this.readCodeWithScope();
  105. case 0x10:
  106. const int32Val = reader.view.getInt32(reader.x, true);
  107. reader.x += 4;
  108. return int32Val;
  109. case 0x11:
  110. return this.readTimestamp();
  111. case 0x12:
  112. const int64Val = reader.view.getBigInt64(reader.x, true);
  113. reader.x += 8;
  114. return Number(int64Val);
  115. case 0x13:
  116. return this.readDecimal128();
  117. case 0xff:
  118. return new values_1.BsonMinKey();
  119. case 0x7f:
  120. return new values_1.BsonMaxKey();
  121. default:
  122. throw new Error(`Unsupported BSON type: 0x${type.toString(16)}`);
  123. }
  124. }
  125. readArray() {
  126. const doc = this.readDocument();
  127. const keys = Object.keys(doc).sort((a, b) => parseInt(a, 10) - parseInt(b, 10));
  128. return keys.map((key) => doc[key]);
  129. }
  130. readBinary() {
  131. const reader = this.reader;
  132. const length = reader.view.getInt32(reader.x, true);
  133. reader.x += 4;
  134. const subtype = reader.u8();
  135. const data = reader.buf(length);
  136. if (subtype === 0) {
  137. return data;
  138. }
  139. return new values_1.BsonBinary(subtype, data);
  140. }
  141. readObjectId() {
  142. const reader = this.reader;
  143. const uint8 = reader.uint8;
  144. const x = reader.x;
  145. const timestamp = (uint8[x] << 24) | (uint8[x + 1] << 16) | (uint8[x + 2] << 8) | uint8[x + 3];
  146. const processLo = uint8[x + 4] | (uint8[x + 5] << 8) | (uint8[x + 6] << 16) | (uint8[x + 7] << 24);
  147. const processHi = uint8[x + 8];
  148. const processLoUnsigned = processLo >>> 0;
  149. const process = processLoUnsigned + processHi * 0x100000000;
  150. const counter = (uint8[x + 9] << 16) | (uint8[x + 10] << 8) | uint8[x + 11];
  151. reader.x += 12;
  152. return new values_1.BsonObjectId(timestamp, process, counter);
  153. }
  154. readRegex() {
  155. const pattern = this.readCString();
  156. const flags = this.readCString();
  157. return new RegExp(pattern, flags);
  158. }
  159. readDbPointer() {
  160. const name = this.readString();
  161. const id = this.readObjectId();
  162. return new values_1.BsonDbPointer(name, id);
  163. }
  164. readCodeWithScope() {
  165. const reader = this.reader;
  166. const totalLength = reader.view.getInt32(reader.x, true);
  167. reader.x += 4;
  168. const code = this.readString();
  169. const scope = this.readDocument();
  170. return new values_1.BsonJavascriptCodeWithScope(code, scope);
  171. }
  172. readTimestamp() {
  173. const reader = this.reader;
  174. const increment = reader.view.getInt32(reader.x, true);
  175. reader.x += 4;
  176. const timestamp = reader.view.getInt32(reader.x, true);
  177. reader.x += 4;
  178. return new values_1.BsonTimestamp(increment, timestamp);
  179. }
  180. readDecimal128() {
  181. const reader = this.reader;
  182. const data = reader.buf(16);
  183. return new values_1.BsonDecimal128(data);
  184. }
  185. }
  186. exports.BsonDecoder = BsonDecoder;
  187. //# sourceMappingURL=BsonDecoder.js.map