json.js 18 KB

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