| author | Tom Parker <palfrey@lshift.net> |
| Fri Dec 03 12:19:42 2010 +0000 (14 months ago) | |
| changeset 278 | 18023c8db394 |
| parent 94 | json.js@b8740380cf08 |
| permissions | -rw-r--r-- |
1 /*
2 Copyright (c) 2005 JSON.org
3 Copyright (c) 2005, 2006 tonyg@kcbbs.gen.nz
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:
12 The Software shall be used for Good, not Evil.
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.
23 CHANGELOG
24 =========
26 - September 2005: changes by tonyg@kcbbs.gen.nz for constructors and
27 customisable serialisation
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
33 */
35 var JSON = {
36 org: 'http://www.JSON.org',
37 copyright: '(c)2005 JSON.org',
38 license: 'http://www.crockford.com/JSON/license.html',
40 javaSerializers: {
41 "java.lang.Object": function (arg) { return JSON.stringify(String(arg)); }
42 },
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 },
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 },
71 stringify: function (arg) {
72 var c, i, l, s = '', v;
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;
84 }
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 }
103 }
104 return '{' + s + '}';
105 }
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);
141 }
142 }
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 = ' ';
155 function error(m) {
156 throw {
157 name: 'JSONError',
158 message: m,
159 at: at - 1,
160 text: text
161 };
162 }
164 function next() {
165 ch = text.charAt(at);
166 at += 1;
167 return ch;
168 }
170 function white() {
171 while (ch != '' && ch <= ' ') {
172 next();
173 }
174 }
176 function str() {
177 var i, s = '', t, u;
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 }
218 }
219 }
220 error("Bad string");
221 }
223 function arr() {
224 var a = [];
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;
241 }
242 next();
243 white();
244 }
245 }
246 error("Bad array");
247 }
249 function obj() {
250 var k, o = {};
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;
273 }
274 next();
275 white();
276 }
277 }
278 error("Bad object");
279 }
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();
307 }
308 }
309 v = +n;
310 if (!isFinite(v)) {
311 error("Bad number");
312 } else {
313 return v;
314 }
315 }
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;
336 }
337 break;
338 }
339 error("Syntax error");
340 }
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 }
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();
376 }
377 }
379 return val();
380 }
381 };