bson.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* jshint esversion: 6 */
  2. // Experimental BSON JavaScript reader
  3. var bson = {};
  4. // http://bsonspec.org/spec.html
  5. bson.Reader = class {
  6. constructor(buffer) {
  7. this._asciiDecoder = new TextDecoder('ascii');
  8. this._utf8Decoder = new TextDecoder('utf-8');
  9. this._buffer = buffer;
  10. this._position = 0;
  11. this._view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  12. }
  13. read() {
  14. return this.document();
  15. }
  16. document(isArray) {
  17. const start = this._position;
  18. const size = this.int32();
  19. if (size < 5 || start + size > this._buffer.length || this._buffer[start + size - 1] != 0x00) {
  20. throw new bson.Reader('Invalid BSON size.');
  21. }
  22. const element = isArray ? [] : {};
  23. let index = 0;
  24. for (;;) {
  25. const type = this.byte();
  26. if (type == 0x00) {
  27. break;
  28. }
  29. const key = this.cstring();
  30. let value = null;
  31. switch (type) {
  32. case 0x01:
  33. value = this.double();
  34. break;
  35. case 0x02:
  36. value = this.string();
  37. break;
  38. case 0x03:
  39. value = this.document(false);
  40. break;
  41. case 0x04:
  42. value = this.document(true);
  43. break;
  44. case 0x05:
  45. value = this.binary();
  46. break;
  47. case 0x08:
  48. value = this.boolean();
  49. break;
  50. case 0x0A:
  51. value = null;
  52. break;
  53. case 0x10:
  54. value = this.int32();
  55. break;
  56. case 0x11:
  57. value = this.uint64();
  58. break;
  59. case 0x12:
  60. value = this.int64();
  61. break;
  62. default:
  63. throw new bson.Error("Unknown value type '" + type + "'.");
  64. }
  65. if (isArray) {
  66. if (index !== parseInt(key, 10)) {
  67. throw new bson.Error("Invalid array index '" + key + "'.");
  68. }
  69. element.push(value);
  70. index++;
  71. }
  72. else {
  73. element[key] = value;
  74. }
  75. }
  76. return element;
  77. }
  78. cstring() {
  79. const end = this._buffer.indexOf(0x00, this._position);
  80. const value = this._asciiDecoder.decode(this._buffer.subarray(this._position, end));
  81. this._position = end + 1;
  82. return value;
  83. }
  84. string() {
  85. const end = this.int32() + this._position - 1;
  86. const value = this._utf8Decoder.decode(this._buffer.subarray(this._position, end));
  87. this._position = end;
  88. if (this.byte() != '0x00') {
  89. throw new bson.Error('String missing terminal 0.');
  90. }
  91. return value;
  92. }
  93. binary() {
  94. const size = this.int32();
  95. const subtype = this.byte();
  96. const data = this._buffer.subarray(this._position, this._position + size);
  97. this._position += size;
  98. switch (subtype) {
  99. case 0x00:
  100. return data;
  101. default:
  102. throw new bson.Error("Unknown binary subtype '" + subtype + "'.");
  103. }
  104. }
  105. boolean() {
  106. const value = this.byte();
  107. switch (value) {
  108. case 0x00: return false;
  109. case 0x01: return true;
  110. default: throw new bson.Error("Invalid boolean value '" + value + "'.");
  111. }
  112. }
  113. byte() {
  114. return this._buffer[this._position++];
  115. }
  116. int32() {
  117. const value = this._view.getInt32(this._position, true);
  118. this._position += 4;
  119. return value;
  120. }
  121. int64() {
  122. const value = this._view.getInt64(this._position, true).toNumber();
  123. this._position += 8;
  124. return value;
  125. }
  126. uint64() {
  127. const value = this._view.getUint64(this._position, true).toNumber();
  128. this._position += 8;
  129. return value;
  130. }
  131. };
  132. bson.Error = class extends Error {
  133. constructor(message) {
  134. super(message);
  135. this.name = 'BSON Error';
  136. }
  137. };
  138. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  139. module.exports.Reader = bson.Reader;
  140. }