json.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. import * as text from './text.js';
  2. const json = {};
  3. const bson = {};
  4. json.TextReader = class {
  5. static open(data) {
  6. const decoder = text.Decoder.open(data);
  7. let state = '';
  8. for (let i = 0; i < 0x1000; i++) {
  9. const c = decoder.decode();
  10. if (state === 'match') {
  11. break;
  12. }
  13. if (c === undefined || c === '\0') {
  14. if (state === '') {
  15. return null;
  16. }
  17. break;
  18. }
  19. if (c <= ' ') {
  20. if (c !== ' ' && c !== '\n' && c !== '\r' && c !== '\t') {
  21. return null;
  22. }
  23. continue;
  24. }
  25. switch (state) {
  26. case '':
  27. if (c === '{') {
  28. state = '{}';
  29. } else if (c === '[') {
  30. state = '[]';
  31. } else {
  32. return null;
  33. }
  34. break;
  35. case '[]':
  36. if (c !== '"' && c !== '-' && c !== '+' && c !== '{' && c !== '[' && (c < '0' || c > '9')) {
  37. return null;
  38. }
  39. state = 'match';
  40. break;
  41. case '{}':
  42. if (c !== '"') {
  43. return null;
  44. }
  45. state = 'match';
  46. break;
  47. default:
  48. break;
  49. }
  50. }
  51. return new json.TextReader(decoder);
  52. }
  53. constructor(decoder) {
  54. this._decoder = decoder;
  55. this._decoder.position = 0;
  56. this._escape = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' };
  57. }
  58. read() {
  59. const stack = [];
  60. this._decoder.position = 0;
  61. this._position = 0;
  62. this._char = this._decoder.decode();
  63. this._whitespace();
  64. let obj = null;
  65. let first = true;
  66. for (;;) {
  67. if (Array.isArray(obj)) {
  68. this._whitespace();
  69. let c = this._char;
  70. if (c === ']') {
  71. this._next();
  72. this._whitespace();
  73. if (stack.length > 0) {
  74. obj = stack.pop();
  75. first = false;
  76. continue;
  77. }
  78. if (this._char !== undefined) {
  79. this._unexpected();
  80. }
  81. return obj;
  82. }
  83. if (!first) {
  84. if (this._char !== ',') {
  85. this._unexpected();
  86. }
  87. this._next();
  88. this._whitespace();
  89. c = this._char;
  90. }
  91. first = false;
  92. switch (c) {
  93. case '{': {
  94. this._next();
  95. stack.push(obj);
  96. const item = {};
  97. obj.push(item);
  98. obj = item;
  99. first = true;
  100. break;
  101. }
  102. case '[': {
  103. this._next();
  104. stack.push(obj);
  105. const item = [];
  106. obj.push(item);
  107. obj = item;
  108. first = true;
  109. break;
  110. }
  111. default: {
  112. obj.push(c === '"' ? this._string() : this._literal());
  113. break;
  114. }
  115. }
  116. } else if (obj instanceof Object) {
  117. this._whitespace();
  118. let c = this._char;
  119. if (c === '}') {
  120. this._next();
  121. this._whitespace();
  122. if (stack.length > 0) {
  123. obj = stack.pop();
  124. first = false;
  125. continue;
  126. }
  127. if (this._char !== undefined) {
  128. this._unexpected();
  129. }
  130. return obj;
  131. }
  132. if (!first) {
  133. if (this._char !== ',') {
  134. this._unexpected();
  135. }
  136. this._next();
  137. this._whitespace();
  138. c = this._char;
  139. }
  140. first = false;
  141. if (c === '"') {
  142. const key = this._string();
  143. switch (key) {
  144. case '__proto__':
  145. case 'constructor':
  146. throw new json.Error(`Invalid key '${key}' ${this._location()}`);
  147. default:
  148. break;
  149. }
  150. this._whitespace();
  151. if (this._char !== ':') {
  152. this._unexpected();
  153. }
  154. this._next();
  155. this._whitespace();
  156. c = this._char;
  157. switch (c) {
  158. case '{': {
  159. this._next();
  160. stack.push(obj);
  161. const value = {};
  162. obj[key] = value;
  163. obj = value;
  164. first = true;
  165. break;
  166. }
  167. case '[': {
  168. this._next();
  169. stack.push(obj);
  170. const value = [];
  171. obj[key] = value;
  172. obj = value;
  173. first = true;
  174. break;
  175. }
  176. default: {
  177. obj[key] = c === '"' ? this._string() : this._literal();
  178. break;
  179. }
  180. }
  181. this._whitespace();
  182. continue;
  183. }
  184. this._unexpected();
  185. } else {
  186. const c = this._char;
  187. switch (c) {
  188. case '{': {
  189. this._next();
  190. this._whitespace();
  191. obj = {};
  192. first = true;
  193. break;
  194. }
  195. case '[': {
  196. this._next();
  197. this._whitespace();
  198. obj = [];
  199. first = true;
  200. break;
  201. }
  202. default: {
  203. let value = null;
  204. if (c === '"') {
  205. value = this._string();
  206. } else if (c >= '0' && c <= '9') {
  207. value = this._number();
  208. } else {
  209. value = this._literal();
  210. }
  211. this._whitespace();
  212. if (this._char !== undefined) {
  213. this._unexpected();
  214. }
  215. return value;
  216. }
  217. }
  218. }
  219. }
  220. }
  221. _next() {
  222. if (this._char === undefined) {
  223. this._unexpected();
  224. }
  225. this._position = this._decoder.position;
  226. this._char = this._decoder.decode();
  227. }
  228. _whitespace() {
  229. while (this._char === ' ' || this._char === '\n' || this._char === '\r' || this._char === '\t') {
  230. this._next();
  231. }
  232. }
  233. _literal() {
  234. const c = this._char;
  235. if (c >= '0' && c <= '9') {
  236. return this._number();
  237. }
  238. switch (c) {
  239. case 't': this._expect('true'); return true;
  240. case 'f': this._expect('false'); return false;
  241. case 'n': this._expect('null'); return null;
  242. case 'N': this._expect('NaN'); return NaN;
  243. case 'I': this._expect('Infinity'); return Infinity;
  244. case '-': return this._number();
  245. default: this._unexpected();
  246. }
  247. return null;
  248. }
  249. _number() {
  250. let value = '';
  251. if (this._char === '-') {
  252. value = '-';
  253. this._next();
  254. }
  255. if (this._char === 'I') {
  256. this._expect('Infinity');
  257. return -Infinity;
  258. }
  259. const c = this._char;
  260. if (c < '0' || c > '9') {
  261. this._unexpected();
  262. }
  263. value += c;
  264. this._next();
  265. if (c === '0') {
  266. const n = this._char;
  267. if (n >= '0' && n <= '9') {
  268. this._unexpected();
  269. }
  270. }
  271. while (this._char >= '0' && this._char <= '9') {
  272. value += this._char;
  273. this._next();
  274. }
  275. if (this._char === '.') {
  276. value += '.';
  277. this._next();
  278. const n = this._char;
  279. if (n < '0' || n > '9') {
  280. this._unexpected();
  281. }
  282. while (this._char >= '0' && this._char <= '9') {
  283. value += this._char;
  284. this._next();
  285. }
  286. }
  287. if (this._char === 'e' || this._char === 'E') {
  288. value += this._char;
  289. this._next();
  290. const s = this._char;
  291. if (s === '-' || s === '+') {
  292. value += this._char;
  293. this._next();
  294. }
  295. const c = this._char;
  296. if (c < '0' || c > '9') {
  297. this._unexpected();
  298. }
  299. value += this._char;
  300. this._next();
  301. while (this._char >= '0' && this._char <= '9') {
  302. value += this._char;
  303. this._next();
  304. }
  305. }
  306. return Number(value);
  307. }
  308. _string() {
  309. let value = '';
  310. this._next();
  311. while (this._char !== '"') {
  312. if (this._char === '\\') {
  313. this._next();
  314. if (this._char === 'u') {
  315. this._next();
  316. let uffff = 0;
  317. for (let i = 0; i < 4; i ++) {
  318. const hex = parseInt(this._char, 16);
  319. if (!isFinite(hex)) {
  320. this._unexpected();
  321. }
  322. this._next();
  323. uffff = uffff * 16 + hex;
  324. }
  325. value += String.fromCharCode(uffff);
  326. } else if (this._escape[this._char]) {
  327. value += this._escape[this._char];
  328. this._next();
  329. } else {
  330. this._unexpected();
  331. }
  332. } else if (this._char < ' ') {
  333. this._unexpected();
  334. } else {
  335. value += this._char;
  336. this._next();
  337. }
  338. }
  339. this._next();
  340. return value;
  341. }
  342. _expect(value) {
  343. for (let i = 0; i < value.length; i++) {
  344. if (value[i] !== this._char) {
  345. this._unexpected();
  346. }
  347. this._next();
  348. }
  349. }
  350. _unexpected() {
  351. let c = this._char;
  352. if (c === undefined) {
  353. throw new json.Error('Unexpected end of JSON input.');
  354. } else if (c === '"') {
  355. c = 'string';
  356. } else if ((c >= '0' && c <= '9') || c === '-') {
  357. c = 'number';
  358. } else {
  359. if (c < ' ' || c > '\x7F') {
  360. const name = Object.keys(this._escape).filter((key) => this._escape[key] === c);
  361. c = (name.length === 1) ? `\\${name}` : `\\u${(`000${c.charCodeAt(0).toString(16)}`).slice(-4)}`;
  362. }
  363. c = `token '${c}'`;
  364. }
  365. throw new json.Error(`Unexpected ${c} ${this._location()}`);
  366. }
  367. _location() {
  368. let line = 1;
  369. let column = 1;
  370. this._decoder.position = 0;
  371. let c = '';
  372. do {
  373. if (this._decoder.position === this._position) {
  374. return `at ${line}:${column}.`;
  375. }
  376. c = this._decoder.decode();
  377. if (c === '\n') {
  378. line++;
  379. column = 1;
  380. } else {
  381. column++;
  382. }
  383. }
  384. while (c !== undefined);
  385. return `at ${line}:${column}.`;
  386. }
  387. };
  388. json.BinaryReader = class {
  389. static open(data) {
  390. return data ? new json.BinaryReader(data) : null;
  391. }
  392. constructor(data) {
  393. this._buffer = data instanceof Uint8Array ? data : data.peek();
  394. }
  395. read() {
  396. const buffer = this._buffer;
  397. const length = buffer.length;
  398. const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  399. const asciiDecoder = new TextDecoder('ascii');
  400. const utf8Decoder = new TextDecoder('utf-8');
  401. let position = 0;
  402. const skip = (offset) => {
  403. position += offset;
  404. if (position > length) {
  405. throw new bson.Error(`Expected ${position + length} more bytes. The file might be corrupted. Unexpected end of file.`);
  406. }
  407. };
  408. const header = () => {
  409. const start = position;
  410. skip(4);
  411. const size = view.getInt32(start, 4);
  412. if (size < 5 || start + size > length || buffer[start + size - 1] !== 0x00) {
  413. throw new bson.Error('Invalid file size.');
  414. }
  415. };
  416. header();
  417. const stack = [];
  418. let obj = {};
  419. for (;;) {
  420. skip(1);
  421. const type = buffer[position - 1];
  422. if (type === 0x00) {
  423. if (stack.length === 0) {
  424. break;
  425. }
  426. obj = stack.pop();
  427. continue;
  428. }
  429. const start = position;
  430. position = buffer.indexOf(0x00, start) + 1;
  431. const key = asciiDecoder.decode(buffer.subarray(start, position - 1));
  432. let value = null;
  433. switch (type) {
  434. case 0x01: { // float64
  435. const start = position;
  436. skip(8);
  437. value = view.getFloat64(start, true);
  438. break;
  439. }
  440. case 0x02: { // string
  441. skip(4);
  442. const size = view.getInt32(position - 4, true);
  443. const start = position;
  444. skip(size);
  445. value = utf8Decoder.decode(buffer.subarray(start, position - 1));
  446. if (buffer[position - 1] !== 0) {
  447. throw new bson.Error('String missing terminal 0.');
  448. }
  449. break;
  450. }
  451. case 0x03: { // object
  452. header();
  453. value = {};
  454. break;
  455. }
  456. case 0x04: { // array
  457. header();
  458. value = [];
  459. break;
  460. }
  461. case 0x05: { // bytes
  462. const start = position;
  463. skip(5);
  464. const size = view.getInt32(start, true);
  465. const subtype = buffer[start + 4];
  466. if (subtype !== 0x00) {
  467. throw new bson.Error(`Unsupported binary subtype '${subtype}'.`);
  468. }
  469. skip(size);
  470. value = buffer.subarray(start + 5, position);
  471. break;
  472. }
  473. case 0x08: { // boolean
  474. skip(1);
  475. value = buffer[position - 1];
  476. if (value > 1) {
  477. throw new bson.Error(`Invalid boolean value '${value}'.`);
  478. }
  479. value = value === 1 ? true : false;
  480. break;
  481. }
  482. case 0x0A:
  483. value = null;
  484. break;
  485. case 0x10: {
  486. const start = position;
  487. skip(4);
  488. value = view.getInt32(start, true);
  489. break;
  490. }
  491. case 0x11: { // uint64
  492. const start = position;
  493. skip(8);
  494. value = Number(view.getBigUint64(start, true));
  495. break;
  496. }
  497. case 0x12: { // int64
  498. const start = position;
  499. skip(8);
  500. value = Number(view.getBigInt64(start, true));
  501. break;
  502. }
  503. default: {
  504. throw new bson.Error(`Unsupported value type '${type}'.`);
  505. }
  506. }
  507. if (Array.isArray(obj)) {
  508. if (obj.length !== parseInt(key, 10)) {
  509. throw new bson.Error(`Invalid array index '${key}'.`);
  510. }
  511. obj.push(value);
  512. } else {
  513. switch (key) {
  514. case '__proto__':
  515. case 'constructor':
  516. case 'prototype':
  517. throw new bson.Error(`Invalid key '${key}' at ${position}'.`);
  518. default:
  519. break;
  520. }
  521. obj[key] = value;
  522. }
  523. if (type === 0x03 || type === 0x04) {
  524. stack.push(obj);
  525. obj = value;
  526. }
  527. }
  528. if (position !== length) {
  529. throw new bson.Error(`Unexpected data at '${position}'.`);
  530. }
  531. return obj;
  532. }
  533. };
  534. json.Error = class extends Error {
  535. constructor(message) {
  536. super(message);
  537. this.name = 'JSON Error';
  538. }
  539. };
  540. bson.Error = class extends Error {
  541. constructor(message) {
  542. super(message);
  543. this.name = 'BSON Error';
  544. }
  545. };
  546. export const TextReader = json.TextReader;
  547. export const BinaryReader = json.BinaryReader;