!import
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
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 var 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 */
JSON_toString
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
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
append_piece
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
81 function append_piece(aObj) {
82 if (typeof aObj == "string") {
anon:83:60
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
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 */
JSON_fromString
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
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 */
JSON_isMostlyHarmless
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
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 };