priv/server_root/htdocs/json.js
author Tom Parker <palfrey@lshift.net>
Wed Mar 10 14:30:27 2010 +0000 (22 hours ago)
changeset 252 25255b7139e3
parent 94json.js@b8740380cf08
permissions -rw-r--r--
metadata: Hand back NullTags if we find a file we don't know how to get the tags for
     1 /*
     2 Copyright (c) 2005 JSON.org
     3 Copyright (c) 2005, 2006 tonyg@kcbbs.gen.nz
     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:
    11 
    12 The Software shall be used for Good, not Evil.
    13 
    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.
    21 
    22 
    23 CHANGELOG
    24 =========
    25 
    26  - September 2005: changes by tonyg@kcbbs.gen.nz for constructors and
    27    customisable serialisation
    28 
    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 
    33 */
    34 
    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;
    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 = ' ';
   154 
   155         function error(m) {
   156             throw {
   157                 name: 'JSONError',
   158                 message: m,
   159                 at: at - 1,
   160                 text: text
   161             };
   162         }
   163 
   164         function next() {
   165             ch = text.charAt(at);
   166             at += 1;
   167             return ch;
   168         }
   169 
   170         function white() {
   171             while (ch != '' && ch <= ' ') {
   172                 next();
   173             }
   174         }
   175 
   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                     }
   218                 }
   219             }
   220             error("Bad string");
   221         }
   222 
   223         function arr() {
   224             var a = [];
   225 
   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         }
   248 
   249         function obj() {
   250             var k, o = {};
   251 
   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         }
   280 
   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         }
   316 
   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         }
   341 
   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();
   376             }
   377         }
   378 
   379         return val();
   380     }
   381 };