home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 December / PCWorld_2007-12_cd.bin / audio-video / songbird / Songbird_0.3_windows-i686.exe / xulrunner / modules / JSON.jsm next >
Text File  |  2007-09-27  |  7KB  |  179 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Mozilla code.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Simon B├╝nzli <zeniko@gmail.com>
  18.  * Portions created by the Initial Developer are Copyright (C) 2006-2007
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *
  23.  * Alternatively, the contents of this file may be used under the terms of
  24.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  25.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26.  * in which case the provisions of the GPL or the LGPL are applicable instead
  27.  * of those above. If you wish to allow use of your version of this file only
  28.  * under the terms of either the GPL or the LGPL, and not to allow others to
  29.  * use your version of this file under the terms of the MPL, indicate your
  30.  * decision by deleting the provisions above and replace them with the notice
  31.  * and other provisions required by the GPL or the LGPL. If you do not delete
  32.  * the provisions above, a recipient may use your version of this file under
  33.  * the terms of any one of the MPL, the GPL or the LGPL.
  34.  *
  35.  * ***** END LICENSE BLOCK ***** */
  36.  
  37. /**
  38.  * Utilities for JavaScript code to handle JSON content.
  39.  * See http://www.json.org/ for comprehensive information about JSON.
  40.  *
  41.  * Import this module through
  42.  *
  43.  * Components.utils.import("resource://gre/modules/JSON.jsm");
  44.  *
  45.  * Usage:
  46.  *
  47.  * var newJSONString = JSON.toString( GIVEN_JAVASCRIPT_OBJECT );
  48.  * var newJavaScriptObject = JSON.fromString( GIVEN_JSON_STRING );
  49.  *
  50.  * Note: For your own safety, Objects/Arrays returned by
  51.  *       JSON.fromString aren't instanceof Object/Array.
  52.  */
  53.  
  54. EXPORTED_SYMBOLS = ["JSON"];
  55.  
  56. // The following code is a loose adaption of Douglas Crockford's code
  57. // from http://www.json.org/json.js (public domain'd)
  58.  
  59. // Notable differences:
  60. // * Unserializable values such as |undefined| or functions aren't
  61. //   silently dropped but always lead to a TypeError.
  62. // * An optional key blacklist has been added to JSON.toString
  63.  
  64. var JSON = {
  65.   /**
  66.    * Converts a JavaScript object into a JSON string.
  67.    *
  68.    * @param aJSObject is the object to be converted
  69.    * @param aKeysToDrop is an optional array of keys which will be
  70.    *                    ignored in all objects during the serialization
  71.    * @return the object's JSON representation
  72.    *
  73.    * Note: aJSObject MUST not contain cyclic references.
  74.    */
  75.   toString: function JSON_toString(aJSObject, aKeysToDrop) {
  76.     // we use a single string builder for efficiency reasons
  77.     var pieces = [];
  78.     
  79.     // this recursive function walks through all objects and appends their
  80.     // JSON representation (in one or several pieces) to the string builder
  81.     function append_piece(aObj) {
  82.       if (typeof aObj == "string") {
  83.         aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) {
  84.           // use the special escape notation if one exists, otherwise
  85.           // produce a general unicode escape sequence
  86.           switch ($0) {
  87.           case "\b": return "\\b";
  88.           case "\t": return "\\t";
  89.           case "\n": return "\\n";
  90.           case "\f": return "\\f";
  91.           case "\r": return "\\r";
  92.           case '"':  return '\\"';
  93.           case "\\": return "\\\\";
  94.           }
  95.           return "\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4);
  96.         });
  97.         pieces.push('"' + aObj + '"')
  98.       }
  99.       else if (typeof aObj == "boolean") {
  100.         pieces.push(aObj ? "true" : "false");
  101.       }
  102.       else if (typeof aObj == "number" && isFinite(aObj)) {
  103.         // there is no representation for infinite numbers or for NaN!
  104.         pieces.push(aObj.toString());
  105.       }
  106.       else if (aObj === null) {
  107.         pieces.push("null");
  108.       }
  109.       // if it looks like an array, treat it as such - this is required
  110.       // for all arrays from either outside this module or a sandbox
  111.       else if (aObj instanceof Array ||
  112.                typeof aObj == "object" && "length" in aObj &&
  113.                (aObj.length === 0 || aObj[aObj.length - 1] !== undefined)) {
  114.         pieces.push("[");
  115.         for (var i = 0; i < aObj.length; i++) {
  116.           arguments.callee(aObj[i]);
  117.           pieces.push(",");
  118.         }
  119.         if (aObj.length > 0)
  120.           pieces.pop(); // drop the trailing colon
  121.         pieces.push("]");
  122.       }
  123.       else if (typeof aObj == "object") {
  124.         pieces.push("{");
  125.         for (var key in aObj) {
  126.           // allow callers to pass objects containing private data which
  127.           // they don't want the JSON string to contain (so they don't
  128.           // have to manually pre-process the object)
  129.           if (aKeysToDrop && aKeysToDrop.indexOf(key) != -1)
  130.             continue;
  131.           
  132.           arguments.callee(key.toString());
  133.           pieces.push(":");
  134.           arguments.callee(aObj[key]);
  135.           pieces.push(",");
  136.         }
  137.         if (pieces[pieces.length - 1] == ",")
  138.           pieces.pop(); // drop the trailing colon
  139.         pieces.push("}");
  140.       }
  141.       else {
  142.         throw new TypeError("No JSON representation for this object!");
  143.       }
  144.     }
  145.     append_piece(aJSObject);
  146.     
  147.     return pieces.join("");
  148.   },
  149.  
  150.   /**
  151.    * Converts a JSON string into a JavaScript object.
  152.    *
  153.    * @param aJSONString is the string to be converted
  154.    * @return a JavaScript object for the given JSON representation
  155.    */
  156.   fromString: function JSON_fromString(aJSONString) {
  157.     if (!this.isMostlyHarmless(aJSONString))
  158.       throw new SyntaxError("No valid JSON string!");
  159.     
  160.     var s = new Components.utils.Sandbox("about:blank");
  161.     return Components.utils.evalInSandbox("(" + aJSONString + ")", s);
  162.   },
  163.  
  164.   /**
  165.    * Checks whether the given string contains potentially harmful
  166.    * content which might be executed during its evaluation
  167.    * (no parser, thus not 100% safe! Best to use a Sandbox for evaluation)
  168.    *
  169.    * @param aString is the string to be tested
  170.    * @return a boolean
  171.    */
  172.   isMostlyHarmless: function JSON_isMostlyHarmless(aString) {
  173.     const maybeHarmful = /[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/;
  174.     const jsonStrings = /"(\\.|[^"\\\n\r])*"/g;
  175.     
  176.     return !maybeHarmful.test(aString.replace(jsonStrings, ""));
  177.   }
  178. };
  179.