Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Replace non-dfsg-free json.js with public domain json2.js (but don't …

…rename the file in case people depend on the path).
  • Loading branch information...
commit 7ab174bc5adc3ec4ea73d69849340fa6fe2cd719 1 parent b1ddd26
Simon MacMullen authored November 08, 2012

Showing 1 changed file with 438 additions and 337 deletions. Show diff stats Hide diff stats

  1. 775  test/server_root/htdocs/json.js
775  test/server_root/htdocs/json.js
... ...
@@ -1,381 +1,482 @@
1 1
 /*
2  
-Copyright (c) 2005 JSON.org
3  
-Copyright (c) 2005, 2006 tonyg@kcbbs.gen.nz
  2
+    http://www.JSON.org/json2.js
  3
+    2010-08-25
4 4
 
5  
-Permission is hereby granted, free of charge, to any person obtaining a copy
6  
-of this software and associated documentation files (the "Software"), to deal
7  
-in the Software without restriction, including without limitation the rights
8  
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  
-copies of the Software, and to permit persons to whom the Software is
10  
-furnished to do so, subject to the following conditions:
  5
+    Public Domain.
11 6
 
12  
-The Software shall be used for Good, not Evil.
  7
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
13 8
 
14  
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  
-SOFTWARE.
  9
+    See http://www.JSON.org/js.html
21 10
 
22 11
 
23  
-CHANGELOG
24  
-=========
  12
+    This code should be minified before deployment.
  13
+    See http://javascript.crockford.com/jsmin.html
25 14
 
26  
- - September 2005: changes by tonyg@kcbbs.gen.nz for constructors and
27  
-   customisable serialisation
  15
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
  16
+    NOT CONTROL.
28 17
 
29  
- - 23 June 2006: changes by tonyg@kcbbs.gen.nz for Rhino JS support
30  
- - 24 June 2006: changes by tonyg@kcbbs.gen.nz for better array-detection
31  
- - 8 November 2006: tonyg: conditionalise Java-specific code
32 18
 
33  
-*/
  19
+    This file creates a global JSON object containing two methods: stringify
  20
+    and parse.
34 21
 
35  
-var JSON = {
36  
-    org: 'http://www.JSON.org',
37  
-    copyright: '(c)2005 JSON.org',
38  
-    license: 'http://www.crockford.com/JSON/license.html',
39  
-
40  
-    javaSerializers: {
41  
-	"java.lang.Object": function (arg) { return JSON.stringify(String(arg)); }
42  
-    },
43  
-
44  
-    rhinoSupport: false, /* set to true to enable Java JSON serialization */
45  
-    isJavaObject: function (o) {
46  
-	if (this.rhinoSupport) {
47  
-	    if (o instanceof java.lang.Object) {
48  
-		return true;
49  
-	    }
50  
-	}
51  
-	return false;
52  
-    },
53  
-
54  
-    findJavaSerializer: function (o) {
55  
-	var c = o.getClass();
56  
-	while (c != null) {
57  
-	    if (typeof this.javaSerializers[c.getName()] != 'undefined') {
58  
-		return this.javaSerializers[c.getName()];
59  
-	    }
60  
-	    var interfaces = c.getInterfaces();
61  
-	    for (var i = 0; i < interfaces.length; i++) {
62  
-		if (typeof this.javaSerializers[interfaces[i].getName()] != 'undefined') {
63  
-		    return this.javaSerializers[interfaces[i].getName()];
64  
-		}
65  
-	    }
66  
-	    c = c.getSuperclass();
67  
-	}
68  
-	return null;
69  
-    },
70  
-
71  
-    stringify: function (arg) {
72  
-        var c, i, l, s = '', v;
73  
-
74  
-        switch (typeof arg) {
75  
-        case 'object':
76  
-            if (arg) {
77  
-                if (arg instanceof Array) {
78  
-                    for (i = 0; i < arg.length; ++i) {
79  
-                        v = this.stringify(arg[i]);
80  
-                        if (s) {
81  
-                            s += ',';
82  
-                        }
83  
-                        s += v;
  22
+        JSON.stringify(value, replacer, space)
  23
+            value       any JavaScript value, usually an object or array.
  24
+
  25
+            replacer    an optional parameter that determines how object
  26
+                        values are stringified for objects. It can be a
  27
+                        function or an array of strings.
  28
+
  29
+            space       an optional parameter that specifies the indentation
  30
+                        of nested structures. If it is omitted, the text will
  31
+                        be packed without extra whitespace. If it is a number,
  32
+                        it will specify the number of spaces to indent at each
  33
+                        level. If it is a string (such as '\t' or '&nbsp;'),
  34
+                        it contains the characters used to indent at each level.
  35
+
  36
+            This method produces a JSON text from a JavaScript value.
  37
+
  38
+            When an object value is found, if the object contains a toJSON
  39
+            method, its toJSON method will be called and the result will be
  40
+            stringified. A toJSON method does not serialize: it returns the
  41
+            value represented by the name/value pair that should be serialized,
  42
+            or undefined if nothing should be serialized. The toJSON method
  43
+            will be passed the key associated with the value, and this will be
  44
+            bound to the value
  45
+
  46
+            For example, this would serialize Dates as ISO strings.
  47
+
  48
+                Date.prototype.toJSON = function (key) {
  49
+                    function f(n) {
  50
+                        // Format integers to have at least two digits.
  51
+                        return n < 10 ? '0' + n : n;
84 52
                     }
85  
-                    return '[' + s + ']';
86  
-		} else if (typeof arg.toJsonString != 'undefined') {
87  
-		    return arg.toJsonString();
88  
-		} else if (this.isJavaObject(arg)) {
89  
-		    v = this.findJavaSerializer(arg);
90  
-		    if (v != null) {
91  
-			return v(arg);
92  
-		    }
93  
-                } else if (typeof arg.toString != 'undefined') {
94  
-                    for (i in arg) {
95  
-                        v = arg[i];
96  
-                        if (typeof v != 'undefined' && typeof v != 'function') {
97  
-                            v = this.stringify(v);
98  
-                            if (s) {
99  
-                                s += ',';
100  
-                            }
101  
-                            s += this.stringify(i) + ':' + v;
102  
-                        }
  53
+
  54
+                    return this.getUTCFullYear()   + '-' +
  55
+                         f(this.getUTCMonth() + 1) + '-' +
  56
+                         f(this.getUTCDate())      + 'T' +
  57
+                         f(this.getUTCHours())     + ':' +
  58
+                         f(this.getUTCMinutes())   + ':' +
  59
+                         f(this.getUTCSeconds())   + 'Z';
  60
+                };
  61
+
  62
+            You can provide an optional replacer method. It will be passed the
  63
+            key and value of each member, with this bound to the containing
  64
+            object. The value that is returned from your method will be
  65
+            serialized. If your method returns undefined, then the member will
  66
+            be excluded from the serialization.
  67
+
  68
+            If the replacer parameter is an array of strings, then it will be
  69
+            used to select the members to be serialized. It filters the results
  70
+            such that only members with keys listed in the replacer array are
  71
+            stringified.
  72
+
  73
+            Values that do not have JSON representations, such as undefined or
  74
+            functions, will not be serialized. Such values in objects will be
  75
+            dropped; in arrays they will be replaced with null. You can use
  76
+            a replacer function to replace those with JSON values.
  77
+            JSON.stringify(undefined) returns undefined.
  78
+
  79
+            The optional space parameter produces a stringification of the
  80
+            value that is filled with line breaks and indentation to make it
  81
+            easier to read.
  82
+
  83
+            If the space parameter is a non-empty string, then that string will
  84
+            be used for indentation. If the space parameter is a number, then
  85
+            the indentation will be that many spaces.
  86
+
  87
+            Example:
  88
+
  89
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
  90
+            // text is '["e",{"pluribus":"unum"}]'
  91
+
  92
+
  93
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
  94
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
  95
+
  96
+            text = JSON.stringify([new Date()], function (key, value) {
  97
+                return this[key] instanceof Date ?
  98
+                    'Date(' + this[key] + ')' : value;
  99
+            });
  100
+            // text is '["Date(---current time---)"]'
  101
+
  102
+
  103
+        JSON.parse(text, reviver)
  104
+            This method parses a JSON text to produce an object or array.
  105
+            It can throw a SyntaxError exception.
  106
+
  107
+            The optional reviver parameter is a function that can filter and
  108
+            transform the results. It receives each of the keys and values,
  109
+            and its return value is used instead of the original value.
  110
+            If it returns what it received, then the structure is not modified.
  111
+            If it returns undefined then the member is deleted.
  112
+
  113
+            Example:
  114
+
  115
+            // Parse the text. Values that look like ISO date strings will
  116
+            // be converted to Date objects.
  117
+
  118
+            myData = JSON.parse(text, function (key, value) {
  119
+                var a;
  120
+                if (typeof value === 'string') {
  121
+                    a =
  122
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
  123
+                    if (a) {
  124
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
  125
+                            +a[5], +a[6]));
103 126
                     }
104  
-                    return '{' + s + '}';
105 127
                 }
106  
-            }
107  
-            return 'null';
108  
-        case 'number':
109  
-            return isFinite(arg) ? String(arg) : 'null';
110  
-        case 'string':
111  
-            l = arg.length;
112  
-            s = '"';
113  
-            for (i = 0; i < l; i += 1) {
114  
-                c = arg.charAt(i);
115  
-                if (c >= ' ') {
116  
-                    if (c == '\\' || c == '"') {
117  
-                        s += '\\';
118  
-                    }
119  
-                    s += c;
120  
-                } else {
121  
-                    switch (c) {
122  
-                        case '\b':
123  
-                            s += '\\b';
124  
-                            break;
125  
-                        case '\f':
126  
-                            s += '\\f';
127  
-                            break;
128  
-                        case '\n':
129  
-                            s += '\\n';
130  
-                            break;
131  
-                        case '\r':
132  
-                            s += '\\r';
133  
-                            break;
134  
-                        case '\t':
135  
-                            s += '\\t';
136  
-                            break;
137  
-                        default:
138  
-                            c = c.charCodeAt();
139  
-                            s += '\\u00' + Math.floor(c / 16).toString(16) +
140  
-                                (c % 16).toString(16);
  128
+                return value;
  129
+            });
  130
+
  131
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
  132
+                var d;
  133
+                if (typeof value === 'string' &&
  134
+                        value.slice(0, 5) === 'Date(' &&
  135
+                        value.slice(-1) === ')') {
  136
+                    d = new Date(value.slice(5, -1));
  137
+                    if (d) {
  138
+                        return d;
141 139
                     }
142 140
                 }
143  
-            }
144  
-            return s + '"';
145  
-        case 'boolean':
146  
-            return String(arg);
147  
-        default:
148  
-            return 'null';
149  
-        }
150  
-    },
151  
-    parse: function (text, ctors) {
152  
-        var at = 0;
153  
-        var ch = ' ';
154  
-
155  
-        function error(m) {
156  
-            throw {
157  
-                name: 'JSONError',
158  
-                message: m,
159  
-                at: at - 1,
160  
-                text: text
161  
-            };
  141
+                return value;
  142
+            });
  143
+
  144
+
  145
+    This is a reference implementation. You are free to copy, modify, or
  146
+    redistribute.
  147
+*/
  148
+
  149
+/*jslint evil: true, strict: false */
  150
+
  151
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
  152
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
  153
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
  154
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
  155
+    test, toJSON, toString, valueOf
  156
+*/
  157
+
  158
+
  159
+// Create a JSON object only if one does not already exist. We create the
  160
+// methods in a closure to avoid creating global variables.
  161
+
  162
+if (!this.JSON) {
  163
+    this.JSON = {};
  164
+}
  165
+
  166
+(function () {
  167
+
  168
+    function f(n) {
  169
+        // Format integers to have at least two digits.
  170
+        return n < 10 ? '0' + n : n;
  171
+    }
  172
+
  173
+    if (typeof Date.prototype.toJSON !== 'function') {
  174
+
  175
+        Date.prototype.toJSON = function (key) {
  176
+
  177
+            return isFinite(this.valueOf()) ?
  178
+                   this.getUTCFullYear()   + '-' +
  179
+                 f(this.getUTCMonth() + 1) + '-' +
  180
+                 f(this.getUTCDate())      + 'T' +
  181
+                 f(this.getUTCHours())     + ':' +
  182
+                 f(this.getUTCMinutes())   + ':' +
  183
+                 f(this.getUTCSeconds())   + 'Z' : null;
  184
+        };
  185
+
  186
+        String.prototype.toJSON =
  187
+        Number.prototype.toJSON =
  188
+        Boolean.prototype.toJSON = function (key) {
  189
+            return this.valueOf();
  190
+        };
  191
+    }
  192
+
  193
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  194
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  195
+        gap,
  196
+        indent,
  197
+        meta = {    // table of character substitutions
  198
+            '\b': '\\b',
  199
+            '\t': '\\t',
  200
+            '\n': '\\n',
  201
+            '\f': '\\f',
  202
+            '\r': '\\r',
  203
+            '"' : '\\"',
  204
+            '\\': '\\\\'
  205
+        },
  206
+        rep;
  207
+
  208
+
  209
+    function quote(string) {
  210
+
  211
+// If the string contains no control characters, no quote characters, and no
  212
+// backslash characters, then we can safely slap some quotes around it.
  213
+// Otherwise we must also replace the offending characters with safe escape
  214
+// sequences.
  215
+
  216
+        escapable.lastIndex = 0;
  217
+        return escapable.test(string) ?
  218
+            '"' + string.replace(escapable, function (a) {
  219
+                var c = meta[a];
  220
+                return typeof c === 'string' ? c :
  221
+                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  222
+            }) + '"' :
  223
+            '"' + string + '"';
  224
+    }
  225
+
  226
+
  227
+    function str(key, holder) {
  228
+
  229
+// Produce a string from holder[key].
  230
+
  231
+        var i,          // The loop counter.
  232
+            k,          // The member key.
  233
+            v,          // The member value.
  234
+            length,
  235
+            mind = gap,
  236
+            partial,
  237
+            value = holder[key];
  238
+
  239
+// If the value has a toJSON method, call it to obtain a replacement value.
  240
+
  241
+        if (value && typeof value === 'object' &&
  242
+                typeof value.toJSON === 'function') {
  243
+            value = value.toJSON(key);
162 244
         }
163 245
 
164  
-        function next() {
165  
-            ch = text.charAt(at);
166  
-            at += 1;
167  
-            return ch;
  246
+// If we were called with a replacer function, then call the replacer to
  247
+// obtain a replacement value.
  248
+
  249
+        if (typeof rep === 'function') {
  250
+            value = rep.call(holder, key, value);
168 251
         }
169 252
 
170  
-        function white() {
171  
-            while (ch != '' && ch <= ' ') {
172  
-                next();
  253
+// What happens next depends on the value's type.
  254
+
  255
+        switch (typeof value) {
  256
+        case 'string':
  257
+            return quote(value);
  258
+
  259
+        case 'number':
  260
+
  261
+// JSON numbers must be finite. Encode non-finite numbers as null.
  262
+
  263
+            return isFinite(value) ? String(value) : 'null';
  264
+
  265
+        case 'boolean':
  266
+        case 'null':
  267
+
  268
+// If the value is a boolean or null, convert it to a string. Note:
  269
+// typeof null does not produce 'null'. The case is included here in
  270
+// the remote chance that this gets fixed someday.
  271
+
  272
+            return String(value);
  273
+
  274
+// If the type is 'object', we might be dealing with an object or an array or
  275
+// null.
  276
+
  277
+        case 'object':
  278
+
  279
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
  280
+// so watch out for that case.
  281
+
  282
+            if (!value) {
  283
+                return 'null';
173 284
             }
174  
-        }
175 285
 
176  
-        function str() {
177  
-            var i, s = '', t, u;
178  
-
179  
-            if (ch == '"') {
180  
-outer:          while (next()) {
181  
-                    if (ch == '"') {
182  
-                        next();
183  
-                        return s;
184  
-                    } else if (ch == '\\') {
185  
-                        switch (next()) {
186  
-                        case 'b':
187  
-                            s += '\b';
188  
-                            break;
189  
-                        case 'f':
190  
-                            s += '\f';
191  
-                            break;
192  
-                        case 'n':
193  
-                            s += '\n';
194  
-                            break;
195  
-                        case 'r':
196  
-                            s += '\r';
197  
-                            break;
198  
-                        case 't':
199  
-                            s += '\t';
200  
-                            break;
201  
-                        case 'u':
202  
-                            u = 0;
203  
-                            for (i = 0; i < 4; i += 1) {
204  
-                                t = parseInt(next(), 16);
205  
-                                if (!isFinite(t)) {
206  
-                                    break outer;
207  
-                                }
208  
-                                u = u * 16 + t;
209  
-                            }
210  
-                            s += String.fromCharCode(u);
211  
-                            break;
212  
-                        default:
213  
-                            s += ch;
214  
-                        }
215  
-                    } else {
216  
-                        s += ch;
217  
-                    }
  286
+// Make an array to hold the partial results of stringifying this object value.
  287
+
  288
+            gap += indent;
  289
+            partial = [];
  290
+
  291
+// Is the value an array?
  292
+
  293
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
  294
+
  295
+// The value is an array. Stringify every element. Use null as a placeholder
  296
+// for non-JSON values.
  297
+
  298
+                length = value.length;
  299
+                for (i = 0; i < length; i += 1) {
  300
+                    partial[i] = str(i, value) || 'null';
218 301
                 }
  302
+
  303
+// Join all of the elements together, separated with commas, and wrap them in
  304
+// brackets.
  305
+
  306
+                v = partial.length === 0 ? '[]' :
  307
+                    gap ? '[\n' + gap +
  308
+                            partial.join(',\n' + gap) + '\n' +
  309
+                                mind + ']' :
  310
+                          '[' + partial.join(',') + ']';
  311
+                gap = mind;
  312
+                return v;
219 313
             }
220  
-            error("Bad string");
221  
-        }
222 314
 
223  
-        function arr() {
224  
-            var a = [];
  315
+// If the replacer is an array, use it to select the members to be stringified.
225 316
 
226  
-            if (ch == '[') {
227  
-                next();
228  
-                white();
229  
-                if (ch == ']') {
230  
-                    next();
231  
-                    return a;
232  
-                }
233  
-                while (ch) {
234  
-                    a.push(val());
235  
-                    white();
236  
-                    if (ch == ']') {
237  
-                        next();
238  
-                        return a;
239  
-                    } else if (ch != ',') {
240  
-                        break;
  317
+            if (rep && typeof rep === 'object') {
  318
+                length = rep.length;
  319
+                for (i = 0; i < length; i += 1) {
  320
+                    k = rep[i];
  321
+                    if (typeof k === 'string') {
  322
+                        v = str(k, value);
  323
+                        if (v) {
  324
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
  325
+                        }
241 326
                     }
242  
-                    next();
243  
-                    white();
244 327
                 }
245  
-            }
246  
-            error("Bad array");
247  
-        }
  328
+            } else {
248 329
 
249  
-        function obj() {
250  
-            var k, o = {};
  330
+// Otherwise, iterate through all of the keys in the object.
251 331
 
252  
-            if (ch == '{') {
253  
-                next();
254  
-                white();
255  
-                if (ch == '}') {
256  
-                    next();
257  
-                    return o;
258  
-                }
259  
-                while (ch) {
260  
-                    k = str();
261  
-                    white();
262  
-                    if (ch != ':') {
263  
-                        break;
264  
-                    }
265  
-                    next();
266  
-                    o[k] = val();
267  
-                    white();
268  
-                    if (ch == '}') {
269  
-                        next();
270  
-                        return o;
271  
-                    } else if (ch != ',') {
272  
-                        break;
  332
+                for (k in value) {
  333
+                    if (Object.hasOwnProperty.call(value, k)) {
  334
+                        v = str(k, value);
  335
+                        if (v) {
  336
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
  337
+                        }
273 338
                     }
274  
-                    next();
275  
-                    white();
276 339
                 }
277 340
             }
278  
-            error("Bad object");
  341
+
  342
+// Join all of the member texts together, separated with commas,
  343
+// and wrap them in braces.
  344
+
  345
+            v = partial.length === 0 ? '{}' :
  346
+                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
  347
+                        mind + '}' : '{' + partial.join(',') + '}';
  348
+            gap = mind;
  349
+            return v;
279 350
         }
  351
+    }
280 352
 
281  
-        function num() {
282  
-            var n = '', v;
283  
-            if (ch == '-') {
284  
-                n = '-';
285  
-                next();
286  
-            }
287  
-            while (ch >= '0' && ch <= '9') {
288  
-                n += ch;
289  
-                next();
290  
-            }
291  
-            if (ch == '.') {
292  
-                n += '.';
293  
-                while (next() && ch >= '0' && ch <= '9') {
294  
-                    n += ch;
295  
-                }
296  
-            }
297  
-            if (ch == 'e' || ch == 'E') {
298  
-                n += 'e';
299  
-                next();
300  
-                if (ch == '-' || ch == '+') {
301  
-                    n += ch;
302  
-                    next();
303  
-                }
304  
-                while (ch >= '0' && ch <= '9') {
305  
-                    n += ch;
306  
-                    next();
  353
+// If the JSON object does not yet have a stringify method, give it one.
  354
+
  355
+    if (typeof JSON.stringify !== 'function') {
  356
+        JSON.stringify = function (value, replacer, space) {
  357
+
  358
+// The stringify method takes a value and an optional replacer, and an optional
  359
+// space parameter, and returns a JSON text. The replacer can be a function
  360
+// that can replace values, or an array of strings that will select the keys.
  361
+// A default replacer method can be provided. Use of the space parameter can
  362
+// produce text that is more easily readable.
  363
+
  364
+            var i;
  365
+            gap = '';
  366
+            indent = '';
  367
+
  368
+// If the space parameter is a number, make an indent string containing that
  369
+// many spaces.
  370
+
  371
+            if (typeof space === 'number') {
  372
+                for (i = 0; i < space; i += 1) {
  373
+                    indent += ' ';
307 374
                 }
  375
+
  376
+// If the space parameter is a string, it will be used as the indent string.
  377
+
  378
+            } else if (typeof space === 'string') {
  379
+                indent = space;
308 380
             }
309  
-            v = +n;
310  
-            if (!isFinite(v)) {
311  
-                error("Bad number");
312  
-            } else {
313  
-                return v;
  381
+
  382
+// If there is a replacer, it must be a function or an array.
  383
+// Otherwise, throw an error.
  384
+
  385
+            rep = replacer;
  386
+            if (replacer && typeof replacer !== 'function' &&
  387
+                    (typeof replacer !== 'object' ||
  388
+                     typeof replacer.length !== 'number')) {
  389
+                throw new Error('JSON.stringify');
314 390
             }
315  
-        }
316 391
 
317  
-        function word() {
318  
-            switch (ch) {
319  
-                case 't':
320  
-                    if (next() == 'r' && next() == 'u' && next() == 'e') {
321  
-                        next();
322  
-                        return true;
323  
-                    }
324  
-                    break;
325  
-                case 'f':
326  
-                    if (next() == 'a' && next() == 'l' && next() == 's' &&
327  
-                            next() == 'e') {
328  
-                        next();
329  
-                        return false;
330  
-                    }
331  
-                    break;
332  
-                case 'n':
333  
-                    if (next() == 'u' && next() == 'l' && next() == 'l') {
334  
-                        next();
335  
-                        return null;
  392
+// Make a fake root object containing our value under the key of ''.
  393
+// Return the result of stringifying the value.
  394
+
  395
+            return str('', {'': value});
  396
+        };
  397
+    }
  398
+
  399
+
  400
+// If the JSON object does not yet have a parse method, give it one.
  401
+
  402
+    if (typeof JSON.parse !== 'function') {
  403
+        JSON.parse = function (text, reviver) {
  404
+
  405
+// The parse method takes a text and an optional reviver function, and returns
  406
+// a JavaScript value if the text is a valid JSON text.
  407
+
  408
+            var j;
  409
+
  410
+            function walk(holder, key) {
  411
+
  412
+// The walk method is used to recursively walk the resulting structure so
  413
+// that modifications can be made.
  414
+
  415
+                var k, v, value = holder[key];
  416
+                if (value && typeof value === 'object') {
  417
+                    for (k in value) {
  418
+                        if (Object.hasOwnProperty.call(value, k)) {
  419
+                            v = walk(value, k);
  420
+                            if (v !== undefined) {
  421
+                                value[k] = v;
  422
+                            } else {
  423
+                                delete value[k];
  424
+                            }
  425
+                        }
336 426
                     }
337  
-                    break;
  427
+                }
  428
+                return reviver.call(holder, key, value);
338 429
             }
339  
-            error("Syntax error");
340  
-        }
341 430
 
342  
-	function ctor() {
343  
-	    var name = '';
344  
-	    if (ch == '@') {
345  
-		next();
346  
-		while (ch == '.' || (ch.toUpperCase() >= 'A' &&
347  
-				     ch.toUpperCase() <= 'Z')) {
348  
-		    name += ch;
349  
-		    next();
350  
-		}
351  
-		var arg = val();
352  
-		if (name in ctors) {
353  
-		    return ctors[name](arg);
354  
-		} else {
355  
-		    error("Unknown ctor " + name);
356  
-		}
357  
-	    }
358  
-	    error("Bad ctor");
359  
-	}
360  
-
361  
-        function val() {
362  
-            white();
363  
-            switch (ch) {
364  
-	        case '@':
365  
-		    return ctor();
366  
-                case '{':
367  
-                    return obj();
368  
-                case '[':
369  
-                    return arr();
370  
-                case '"':
371  
-                    return str();
372  
-                case '-':
373  
-                    return num();
374  
-                default:
375  
-                    return ch >= '0' && ch <= '9' ? num() : word();
  431
+
  432
+// Parsing happens in four stages. In the first stage, we replace certain
  433
+// Unicode characters with escape sequences. JavaScript handles many characters
  434
+// incorrectly, either silently deleting them, or treating them as line endings.
  435
+
  436
+            text = String(text);
  437
+            cx.lastIndex = 0;
  438
+            if (cx.test(text)) {
  439
+                text = text.replace(cx, function (a) {
  440
+                    return '\\u' +
  441
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  442
+                });
376 443
             }
377  
-        }
378 444
 
379  
-        return val();
  445
+// In the second stage, we run the text against regular expressions that look
  446
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
  447
+// because they can cause invocation, and '=' because it can cause mutation.
  448
+// But just to be safe, we want to reject all unexpected forms.
  449
+
  450
+// We split the second stage into 4 regexp operations in order to work around
  451
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
  452
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
  453
+// replace all simple value tokens with ']' characters. Third, we delete all
  454
+// open brackets that follow a colon or comma or that begin the text. Finally,
  455
+// we look to see that the remaining characters are only whitespace or ']' or
  456
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
  457
+
  458
+            if (/^[\],:{}\s]*$/
  459
+.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
  460
+.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
  461
+.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
  462
+
  463
+// In the third stage we use the eval function to compile the text into a
  464
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
  465
+// in JavaScript: it can begin a block or an object literal. We wrap the text
  466
+// in parens to eliminate the ambiguity.
  467
+
  468
+                j = eval('(' + text + ')');
  469
+
  470
+// In the optional fourth stage, we recursively walk the new structure, passing
  471
+// each name/value pair to a reviver function for possible transformation.
  472
+
  473
+                return typeof reviver === 'function' ?
  474
+                    walk({'': j}, '') : j;
  475
+            }
  476
+
  477
+// If the text is not JSON parseable, then a SyntaxError is thrown.
  478
+
  479
+            throw new SyntaxError('JSON.parse');
  480
+        };
380 481
     }
381  
-};
  482
+}());

0 notes on commit 7ab174b

Please sign in to comment.
Something went wrong with that request. Please try again.