json.js 17 KB

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