| | 1641 | |
|---|
| | 1642 | /******************* JSON PARSER ***********************************************/ |
|---|
| | 1643 | /* |
|---|
| | 1644 | http://www.JSON.org/json2.js |
|---|
| | 1645 | 2009-04-16 |
|---|
| | 1646 | |
|---|
| | 1647 | Public Domain. |
|---|
| | 1648 | |
|---|
| | 1649 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. |
|---|
| | 1650 | |
|---|
| | 1651 | See http://www.JSON.org/js.html |
|---|
| | 1652 | |
|---|
| | 1653 | This file creates a global JSON object containing two methods: stringify |
|---|
| | 1654 | and parse. |
|---|
| | 1655 | |
|---|
| | 1656 | JSON.stringify(value, replacer, space) |
|---|
| | 1657 | value any JavaScript value, usually an object or array. |
|---|
| | 1658 | |
|---|
| | 1659 | replacer an optional parameter that determines how object |
|---|
| | 1660 | values are stringified for objects. It can be a |
|---|
| | 1661 | function or an array of strings. |
|---|
| | 1662 | |
|---|
| | 1663 | space an optional parameter that specifies the indentation |
|---|
| | 1664 | of nested structures. If it is omitted, the text will |
|---|
| | 1665 | be packed without extra whitespace. If it is a number, |
|---|
| | 1666 | it will specify the number of spaces to indent at each |
|---|
| | 1667 | level. If it is a string (such as '\t' or ' '), |
|---|
| | 1668 | it contains the characters used to indent at each level. |
|---|
| | 1669 | |
|---|
| | 1670 | This method produces a JSON text from a JavaScript value. |
|---|
| | 1671 | |
|---|
| | 1672 | When an object value is found, if the object contains a toJSON |
|---|
| | 1673 | method, its toJSON method will be called and the result will be |
|---|
| | 1674 | stringified. A toJSON method does not serialize: it returns the |
|---|
| | 1675 | value represented by the name/value pair that should be serialized, |
|---|
| | 1676 | or undefined if nothing should be serialized. The toJSON method |
|---|
| | 1677 | will be passed the key associated with the value, and this will be |
|---|
| | 1678 | bound to the object holding the key. |
|---|
| | 1679 | |
|---|
| | 1680 | For example, this would serialize Dates as ISO strings. |
|---|
| | 1681 | |
|---|
| | 1682 | Date.prototype.toJSON = function (key) { |
|---|
| | 1683 | function f(n) { |
|---|
| | 1684 | // Format integers to have at least two digits. |
|---|
| | 1685 | return n < 10 ? '0' + n : n; |
|---|
| | 1686 | } |
|---|
| | 1687 | |
|---|
| | 1688 | return this.getUTCFullYear() + '-' + |
|---|
| | 1689 | f(this.getUTCMonth() + 1) + '-' + |
|---|
| | 1690 | f(this.getUTCDate()) + 'T' + |
|---|
| | 1691 | f(this.getUTCHours()) + ':' + |
|---|
| | 1692 | f(this.getUTCMinutes()) + ':' + |
|---|
| | 1693 | f(this.getUTCSeconds()) + 'Z'; |
|---|
| | 1694 | }; |
|---|
| | 1695 | |
|---|
| | 1696 | You can provide an optional replacer method. It will be passed the |
|---|
| | 1697 | key and value of each member, with this bound to the containing |
|---|
| | 1698 | object. The value that is returned from your method will be |
|---|
| | 1699 | serialized. If your method returns undefined, then the member will |
|---|
| | 1700 | be excluded from the serialization. |
|---|
| | 1701 | |
|---|
| | 1702 | If the replacer parameter is an array of strings, then it will be |
|---|
| | 1703 | used to select the members to be serialized. It filters the results |
|---|
| | 1704 | such that only members with keys listed in the replacer array are |
|---|
| | 1705 | stringified. |
|---|
| | 1706 | |
|---|
| | 1707 | Values that do not have JSON representations, such as undefined or |
|---|
| | 1708 | functions, will not be serialized. Such values in objects will be |
|---|
| | 1709 | dropped; in arrays they will be replaced with null. You can use |
|---|
| | 1710 | a replacer function to replace those with JSON values. |
|---|
| | 1711 | JSON.stringify(undefined) returns undefined. |
|---|
| | 1712 | |
|---|
| | 1713 | The optional space parameter produces a stringification of the |
|---|
| | 1714 | value that is filled with line breaks and indentation to make it |
|---|
| | 1715 | easier to read. |
|---|
| | 1716 | |
|---|
| | 1717 | If the space parameter is a non-empty string, then that string will |
|---|
| | 1718 | be used for indentation. If the space parameter is a number, then |
|---|
| | 1719 | the indentation will be that many spaces. |
|---|
| | 1720 | |
|---|
| | 1721 | Example: |
|---|
| | 1722 | |
|---|
| | 1723 | text = JSON.stringify(['e', {pluribus: 'unum'}]); |
|---|
| | 1724 | // text is '["e",{"pluribus":"unum"}]' |
|---|
| | 1725 | |
|---|
| | 1726 | |
|---|
| | 1727 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); |
|---|
| | 1728 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' |
|---|
| | 1729 | |
|---|
| | 1730 | text = JSON.stringify([new Date()], function (key, value) { |
|---|
| | 1731 | return this[key] instanceof Date ? |
|---|
| | 1732 | 'Date(' + this[key] + ')' : value; |
|---|
| | 1733 | }); |
|---|
| | 1734 | // text is '["Date(---current time---)"]' |
|---|
| | 1735 | |
|---|
| | 1736 | |
|---|
| | 1737 | JSON.parse(text, reviver) |
|---|
| | 1738 | This method parses a JSON text to produce an object or array. |
|---|
| | 1739 | It can throw a SyntaxError exception. |
|---|
| | 1740 | |
|---|
| | 1741 | The optional reviver parameter is a function that can filter and |
|---|
| | 1742 | transform the results. It receives each of the keys and values, |
|---|
| | 1743 | and its return value is used instead of the original value. |
|---|
| | 1744 | If it returns what it received, then the structure is not modified. |
|---|
| | 1745 | If it returns undefined then the member is deleted. |
|---|
| | 1746 | |
|---|
| | 1747 | Example: |
|---|
| | 1748 | |
|---|
| | 1749 | // Parse the text. Values that look like ISO date strings will |
|---|
| | 1750 | // be converted to Date objects. |
|---|
| | 1751 | |
|---|
| | 1752 | myData = JSON.parse(text, function (key, value) { |
|---|
| | 1753 | var a; |
|---|
| | 1754 | if (typeof value === 'string') { |
|---|
| | 1755 | a = |
|---|
| | 1756 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); |
|---|
| | 1757 | if (a) { |
|---|
| | 1758 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], |
|---|
| | 1759 | +a[5], +a[6])); |
|---|
| | 1760 | } |
|---|
| | 1761 | } |
|---|
| | 1762 | return value; |
|---|
| | 1763 | }); |
|---|
| | 1764 | |
|---|
| | 1765 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { |
|---|
| | 1766 | var d; |
|---|
| | 1767 | if (typeof value === 'string' && |
|---|
| | 1768 | value.slice(0, 5) === 'Date(' && |
|---|
| | 1769 | value.slice(-1) === ')') { |
|---|
| | 1770 | d = new Date(value.slice(5, -1)); |
|---|
| | 1771 | if (d) { |
|---|
| | 1772 | return d; |
|---|
| | 1773 | } |
|---|
| | 1774 | } |
|---|
| | 1775 | return value; |
|---|
| | 1776 | }); |
|---|
| | 1777 | |
|---|
| | 1778 | |
|---|
| | 1779 | This is a reference implementation. You are free to copy, modify, or |
|---|
| | 1780 | redistribute. |
|---|
| | 1781 | |
|---|
| | 1782 | This code should be minified before deployment. |
|---|
| | 1783 | See http://javascript.crockford.com/jsmin.html |
|---|
| | 1784 | |
|---|
| | 1785 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO |
|---|
| | 1786 | NOT CONTROL. |
|---|
| | 1787 | */ |
|---|
| | 1788 | |
|---|
| | 1789 | /*jslint evil: true */ |
|---|
| | 1790 | |
|---|
| | 1791 | /*global JSON */ |
|---|
| | 1792 | |
|---|
| | 1793 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, |
|---|
| | 1794 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, |
|---|
| | 1795 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, |
|---|
| | 1796 | lastIndex, length, parse, prototype, push, replace, slice, stringify, |
|---|
| | 1797 | test, toJSON, toString, valueOf |
|---|
| | 1798 | */ |
|---|
| | 1799 | |
|---|
| | 1800 | // Create a JSON object only if one does not already exist. We create the |
|---|
| | 1801 | // methods in a closure to avoid creating global variables. |
|---|
| | 1802 | |
|---|
| | 1803 | if (!this.JSON) { |
|---|
| | 1804 | JSON = {}; |
|---|
| | 1805 | } |
|---|
| | 1806 | (function () { |
|---|
| | 1807 | |
|---|
| | 1808 | function f(n) { |
|---|
| | 1809 | // Format integers to have at least two digits. |
|---|
| | 1810 | return n < 10 ? '0' + n : n; |
|---|
| | 1811 | } |
|---|
| | 1812 | |
|---|
| | 1813 | if (typeof Date.prototype.toJSON !== 'function') { |
|---|
| | 1814 | |
|---|
| | 1815 | Date.prototype.toJSON = function (key) { |
|---|
| | 1816 | |
|---|
| | 1817 | return this.getUTCFullYear() + '-' + |
|---|
| | 1818 | f(this.getUTCMonth() + 1) + '-' + |
|---|
| | 1819 | f(this.getUTCDate()) + 'T' + |
|---|
| | 1820 | f(this.getUTCHours()) + ':' + |
|---|
| | 1821 | f(this.getUTCMinutes()) + ':' + |
|---|
| | 1822 | f(this.getUTCSeconds()) + 'Z'; |
|---|
| | 1823 | }; |
|---|
| | 1824 | |
|---|
| | 1825 | String.prototype.toJSON = |
|---|
| | 1826 | Number.prototype.toJSON = |
|---|
| | 1827 | Boolean.prototype.toJSON = function (key) { |
|---|
| | 1828 | return this.valueOf(); |
|---|
| | 1829 | }; |
|---|
| | 1830 | } |
|---|
| | 1831 | |
|---|
| | 1832 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, |
|---|
| | 1833 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, |
|---|
| | 1834 | gap, |
|---|
| | 1835 | indent, |
|---|
| | 1836 | meta = { // table of character substitutions |
|---|
| | 1837 | '\b': '\\b', |
|---|
| | 1838 | '\t': '\\t', |
|---|
| | 1839 | '\n': '\\n', |
|---|
| | 1840 | '\f': '\\f', |
|---|
| | 1841 | '\r': '\\r', |
|---|
| | 1842 | '"' : '\\"', |
|---|
| | 1843 | '\\': '\\\\' |
|---|
| | 1844 | }, |
|---|
| | 1845 | rep; |
|---|
| | 1846 | |
|---|
| | 1847 | |
|---|
| | 1848 | function quote(string) { |
|---|
| | 1849 | |
|---|
| | 1850 | // If the string contains no control characters, no quote characters, and no |
|---|
| | 1851 | // backslash characters, then we can safely slap some quotes around it. |
|---|
| | 1852 | // Otherwise we must also replace the offending characters with safe escape |
|---|
| | 1853 | // sequences. |
|---|
| | 1854 | |
|---|
| | 1855 | escapable.lastIndex = 0; |
|---|
| | 1856 | return escapable.test(string) ? |
|---|
| | 1857 | '"' + string.replace(escapable, function (a) { |
|---|
| | 1858 | var c = meta[a]; |
|---|
| | 1859 | return typeof c === 'string' ? c : |
|---|
| | 1860 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); |
|---|
| | 1861 | }) + '"' : |
|---|
| | 1862 | '"' + string + '"'; |
|---|
| | 1863 | } |
|---|
| | 1864 | |
|---|
| | 1865 | |
|---|
| | 1866 | function str(key, holder) { |
|---|
| | 1867 | |
|---|
| | 1868 | // Produce a string from holder[key]. |
|---|
| | 1869 | |
|---|
| | 1870 | var i, // The loop counter. |
|---|
| | 1871 | k, // The member key. |
|---|
| | 1872 | v, // The member value. |
|---|
| | 1873 | length, |
|---|
| | 1874 | mind = gap, |
|---|
| | 1875 | partial, |
|---|
| | 1876 | value = holder[key]; |
|---|
| | 1877 | |
|---|
| | 1878 | // If the value has a toJSON method, call it to obtain a replacement value. |
|---|
| | 1879 | |
|---|
| | 1880 | if (value && typeof value === 'object' && |
|---|
| | 1881 | typeof value.toJSON === 'function') { |
|---|
| | 1882 | value = value.toJSON(key); |
|---|
| | 1883 | } |
|---|
| | 1884 | |
|---|
| | 1885 | // If we were called with a replacer function, then call the replacer to |
|---|
| | 1886 | // obtain a replacement value. |
|---|
| | 1887 | |
|---|
| | 1888 | if (typeof rep === 'function') { |
|---|
| | 1889 | value = rep.call(holder, key, value); |
|---|
| | 1890 | } |
|---|
| | 1891 | |
|---|
| | 1892 | // What happens next depends on the value's type. |
|---|
| | 1893 | |
|---|
| | 1894 | switch (typeof value) { |
|---|
| | 1895 | case 'string': |
|---|
| | 1896 | return quote(value); |
|---|
| | 1897 | |
|---|
| | 1898 | case 'number': |
|---|
| | 1899 | |
|---|
| | 1900 | // JSON numbers must be finite. Encode non-finite numbers as null. |
|---|
| | 1901 | |
|---|
| | 1902 | return isFinite(value) ? String(value) : 'null'; |
|---|
| | 1903 | |
|---|
| | 1904 | case 'boolean': |
|---|
| | 1905 | case 'null': |
|---|
| | 1906 | |
|---|
| | 1907 | // If the value is a boolean or null, convert it to a string. Note: |
|---|
| | 1908 | // typeof null does not produce 'null'. The case is included here in |
|---|
| | 1909 | // the remote chance that this gets fixed someday. |
|---|
| | 1910 | |
|---|
| | 1911 | return String(value); |
|---|
| | 1912 | |
|---|
| | 1913 | // If the type is 'object', we might be dealing with an object or an array or |
|---|
| | 1914 | // null. |
|---|
| | 1915 | |
|---|
| | 1916 | case 'object': |
|---|
| | 1917 | |
|---|
| | 1918 | // Due to a specification blunder in ECMAScript, typeof null is 'object', |
|---|
| | 1919 | // so watch out for that case. |
|---|
| | 1920 | |
|---|
| | 1921 | if (!value) { |
|---|
| | 1922 | return 'null'; |
|---|
| | 1923 | } |
|---|
| | 1924 | |
|---|
| | 1925 | // Make an array to hold the partial results of stringifying this object value. |
|---|
| | 1926 | |
|---|
| | 1927 | gap += indent; |
|---|
| | 1928 | partial = []; |
|---|
| | 1929 | |
|---|
| | 1930 | // Is the value an array? |
|---|
| | 1931 | |
|---|
| | 1932 | if (Object.prototype.toString.apply(value) === '[object Array]') { |
|---|
| | 1933 | |
|---|
| | 1934 | // The value is an array. Stringify every element. Use null as a placeholder |
|---|
| | 1935 | // for non-JSON values. |
|---|
| | 1936 | |
|---|
| | 1937 | length = value.length; |
|---|
| | 1938 | for (i = 0; i < length; i += 1) { |
|---|
| | 1939 | partial[i] = str(i, value) || 'null'; |
|---|
| | 1940 | } |
|---|
| | 1941 | |
|---|
| | 1942 | // Join all of the elements together, separated with commas, and wrap them in |
|---|
| | 1943 | // brackets. |
|---|
| | 1944 | |
|---|
| | 1945 | v = partial.length === 0 ? '[]' : |
|---|
| | 1946 | gap ? '[\n' + gap + |
|---|
| | 1947 | partial.join(',\n' + gap) + '\n' + |
|---|
| | 1948 | mind + ']' : |
|---|
| | 1949 | '[' + partial.join(',') + ']'; |
|---|
| | 1950 | gap = mind; |
|---|
| | 1951 | return v; |
|---|
| | 1952 | } |
|---|
| | 1953 | |
|---|
| | 1954 | // If the replacer is an array, use it to select the members to be stringified. |
|---|
| | 1955 | |
|---|
| | 1956 | if (rep && typeof rep === 'object') { |
|---|
| | 1957 | length = rep.length; |
|---|
| | 1958 | for (i = 0; i < length; i += 1) { |
|---|
| | 1959 | k = rep[i]; |
|---|
| | 1960 | if (typeof k === 'string') { |
|---|
| | 1961 | v = str(k, value); |
|---|
| | 1962 | if (v) { |
|---|
| | 1963 | partial.push(quote(k) + (gap ? ': ' : ':') + v); |
|---|
| | 1964 | } |
|---|
| | 1965 | } |
|---|
| | 1966 | } |
|---|
| | 1967 | } else { |
|---|
| | 1968 | |
|---|
| | 1969 | // Otherwise, iterate through all of the keys in the object. |
|---|
| | 1970 | |
|---|
| | 1971 | for (k in value) { |
|---|
| | 1972 | if (Object.hasOwnProperty.call(value, k)) { |
|---|
| | 1973 | v = str(k, value); |
|---|
| | 1974 | if (v) { |
|---|
| | 1975 | partial.push(quote(k) + (gap ? ': ' : ':') + v); |
|---|
| | 1976 | } |
|---|
| | 1977 | } |
|---|
| | 1978 | } |
|---|
| | 1979 | } |
|---|
| | 1980 | |
|---|
| | 1981 | // Join all of the member texts together, separated with commas, |
|---|
| | 1982 | // and wrap them in braces. |
|---|
| | 1983 | |
|---|
| | 1984 | v = partial.length === 0 ? '{}' : |
|---|
| | 1985 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + |
|---|
| | 1986 | mind + '}' : '{' + partial.join(',') + '}'; |
|---|
| | 1987 | gap = mind; |
|---|
| | 1988 | return v; |
|---|
| | 1989 | } |
|---|
| | 1990 | } |
|---|
| | 1991 | |
|---|
| | 1992 | // If the JSON object does not yet have a stringify method, give it one. |
|---|
| | 1993 | |
|---|
| | 1994 | if (typeof JSON.stringify !== 'function') { |
|---|
| | 1995 | JSON.stringify = function (value, replacer, space) { |
|---|
| | 1996 | |
|---|
| | 1997 | // The stringify method takes a value and an optional replacer, and an optional |
|---|
| | 1998 | // space parameter, and returns a JSON text. The replacer can be a function |
|---|
| | 1999 | // that can replace values, or an array of strings that will select the keys. |
|---|
| | 2000 | // A default replacer method can be provided. Use of the space parameter can |
|---|
| | 2001 | // produce text that is more easily readable. |
|---|
| | 2002 | |
|---|
| | 2003 | var i; |
|---|
| | 2004 | gap = ''; |
|---|
| | 2005 | indent = ''; |
|---|
| | 2006 | |
|---|
| | 2007 | // If the space parameter is a number, make an indent string containing that |
|---|
| | 2008 | // many spaces. |
|---|
| | 2009 | |
|---|
| | 2010 | if (typeof space === 'number') { |
|---|
| | 2011 | for (i = 0; i < space; i += 1) { |
|---|
| | 2012 | indent += ' '; |
|---|
| | 2013 | } |
|---|
| | 2014 | |
|---|
| | 2015 | // If the space parameter is a string, it will be used as the indent string. |
|---|
| | 2016 | |
|---|
| | 2017 | } else if (typeof space === 'string') { |
|---|
| | 2018 | indent = space; |
|---|
| | 2019 | } |
|---|
| | 2020 | |
|---|
| | 2021 | // If there is a replacer, it must be a function or an array. |
|---|
| | 2022 | // Otherwise, throw an error. |
|---|
| | 2023 | |
|---|
| | 2024 | rep = replacer; |
|---|
| | 2025 | if (replacer && typeof replacer !== 'function' && |
|---|
| | 2026 | (typeof replacer !== 'object' || |
|---|
| | 2027 | typeof replacer.length !== 'number')) { |
|---|
| | 2028 | throw new Error('JSON.stringify'); |
|---|
| | 2029 | } |
|---|
| | 2030 | |
|---|
| | 2031 | // Make a fake root object containing our value under the key of ''. |
|---|
| | 2032 | // Return the result of stringifying the value. |
|---|
| | 2033 | |
|---|
| | 2034 | return str('', {'': value}); |
|---|
| | 2035 | }; |
|---|
| | 2036 | } |
|---|
| | 2037 | |
|---|
| | 2038 | |
|---|
| | 2039 | // If the JSON object does not yet have a parse method, give it one. |
|---|
| | 2040 | |
|---|
| | 2041 | if (typeof JSON.parse !== 'function') { |
|---|
| | 2042 | JSON.parse = function (text, reviver) { |
|---|
| | 2043 | |
|---|
| | 2044 | // The parse method takes a text and an optional reviver function, and returns |
|---|
| | 2045 | // a JavaScript value if the text is a valid JSON text. |
|---|
| | 2046 | |
|---|
| | 2047 | var j; |
|---|
| | 2048 | |
|---|
| | 2049 | function walk(holder, key) { |
|---|
| | 2050 | |
|---|
| | 2051 | // The walk method is used to recursively walk the resulting structure so |
|---|
| | 2052 | // that modifications can be made. |
|---|
| | 2053 | |
|---|
| | 2054 | var k, v, value = holder[key]; |
|---|
| | 2055 | if (value && typeof value === 'object') { |
|---|
| | 2056 | for (k in value) { |
|---|
| | 2057 | if (Object.hasOwnProperty.call(value, k)) { |
|---|
| | 2058 | v = walk(value, k); |
|---|
| | 2059 | if (v !== undefined) { |
|---|
| | 2060 | value[k] = v; |
|---|
| | 2061 | } else { |
|---|
| | 2062 | delete value[k]; |
|---|
| | 2063 | } |
|---|
| | 2064 | } |
|---|
| | 2065 | } |
|---|
| | 2066 | } |
|---|
| | 2067 | return reviver.call(holder, key, value); |
|---|
| | 2068 | } |
|---|
| | 2069 | |
|---|
| | 2070 | |
|---|
| | 2071 | // Parsing happens in four stages. In the first stage, we replace certain |
|---|
| | 2072 | // Unicode characters with escape sequences. JavaScript handles many characters |
|---|
| | 2073 | // incorrectly, either silently deleting them, or treating them as line endings. |
|---|
| | 2074 | |
|---|
| | 2075 | cx.lastIndex = 0; |
|---|
| | 2076 | if (cx.test(text)) { |
|---|
| | 2077 | text = text.replace(cx, function (a) { |
|---|
| | 2078 | return '\\u' + |
|---|
| | 2079 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); |
|---|
| | 2080 | }); |
|---|
| | 2081 | } |
|---|
| | 2082 | |
|---|
| | 2083 | // In the second stage, we run the text against regular expressions that look |
|---|
| | 2084 | // for non-JSON patterns. We are especially concerned with '()' and 'new' |
|---|
| | 2085 | // because they can cause invocation, and '=' because it can cause mutation. |
|---|
| | 2086 | // But just to be safe, we want to reject all unexpected forms. |
|---|
| | 2087 | |
|---|
| | 2088 | // We split the second stage into 4 regexp operations in order to work around |
|---|
| | 2089 | // crippling inefficiencies in IE's and Safari's regexp engines. First we |
|---|
| | 2090 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we |
|---|
| | 2091 | // replace all simple value tokens with ']' characters. Third, we delete all |
|---|
| | 2092 | // open brackets that follow a colon or comma or that begin the text. Finally, |
|---|
| | 2093 | // we look to see that the remaining characters are only whitespace or ']' or |
|---|
| | 2094 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. |
|---|
| | 2095 | |
|---|
| | 2096 | if (/^[\],:{}\s]*$/. |
|---|
| | 2097 | test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). |
|---|
| | 2098 | replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). |
|---|
| | 2099 | replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { |
|---|
| | 2100 | |
|---|
| | 2101 | // In the third stage we use the eval function to compile the text into a |
|---|
| | 2102 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity |
|---|
| | 2103 | // in JavaScript: it can begin a block or an object literal. We wrap the text |
|---|
| | 2104 | // in parens to eliminate the ambiguity. |
|---|
| | 2105 | |
|---|
| | 2106 | j = eval('(' + text + ')'); |
|---|
| | 2107 | |
|---|
| | 2108 | // In the optional fourth stage, we recursively walk the new structure, passing |
|---|
| | 2109 | // each name/value pair to a reviver function for possible transformation. |
|---|
| | 2110 | |
|---|
| | 2111 | return typeof reviver === 'function' ? |
|---|
| | 2112 | walk({'': j}, '') : j; |
|---|
| | 2113 | } |
|---|
| | 2114 | |
|---|
| | 2115 | // If the text is not JSON parseable, then a SyntaxError is thrown. |
|---|
| | 2116 | |
|---|
| | 2117 | throw new SyntaxError('JSON.parse'); |
|---|
| | 2118 | }; |
|---|
| | 2119 | } |
|---|
| | 2120 | }()); |
|---|