summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/secure/fromJson.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dojox/secure/fromJson.js')
-rw-r--r--js/dojo/dojox/secure/fromJson.js245
1 files changed, 245 insertions, 0 deletions
diff --git a/js/dojo/dojox/secure/fromJson.js b/js/dojo/dojox/secure/fromJson.js
new file mode 100644
index 0000000..263be3a
--- /dev/null
+++ b/js/dojo/dojox/secure/fromJson.js
@@ -0,0 +1,245 @@
+//>>built
+// wrapped by build app
+define("dojox/secure/fromJson", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
+dojo.provide("dojox.secure.fromJson");
+
+// Used with permission from Mike Samuel of Google (has CCLA), from the json-sans-eval project:
+// http://code.google.com/p/json-sans-eval/
+// Mike Samuel <mikesamuel@gmail.com>
+
+
+
+dojox.secure.fromJson = typeof JSON != "undefined" ? JSON.parse :
+// summary:
+// Parses a string of well-formed JSON text.
+// description:
+// Parses a string of well-formed JSON text. If the input is not well-formed,
+// then behavior is undefined, but it is
+// deterministic and is guaranteed not to modify any object other than its
+// return value.
+//
+// This does not use `eval` so is less likely to have obscure security bugs than
+// json2.js.
+// It is optimized for speed, so is much faster than json_parse.js.
+//
+// This library should be used whenever security is a concern (when JSON may
+// come from an untrusted source), speed is a concern, and erroring on malformed
+// JSON is *not* a concern.
+//
+// json2.js is very fast, but potentially insecure since it calls `eval` to
+// parse JSON data, so an attacker might be able to supply strange JS that
+// looks like JSON, but that executes arbitrary javascript.
+//
+// To configure dojox.secure.fromJson as the JSON parser for all Dojo
+// JSON parsing, simply do:
+// | dojo.require("dojox.secure.fromJson");
+// | dojo.fromJson = dojox.secure.fromJson;
+// or alternately you could configure dojox.secure.fromJson to only handle
+// XHR responses:
+// | dojo._contentHandlers.json = function(xhr){
+// | return dojox.secure.fromJson.fromJson(xhr.responseText);
+// | };
+//
+// json: String
+// per RFC 4627
+// optReviver: Function (this:Object, string, *)
+// optional function
+// that reworks JSON objects post-parse per Chapter 15.12 of EcmaScript3.1.
+// If supplied, the function is called with a string key, and a value.
+// The value is the property of 'this'. The reviver should return
+// the value to use in its place. So if dates were serialized as
+// {@code { "type": "Date", "time": 1234 }}, then a reviver might look like
+// {@code
+// function (key, value) {
+// if (value && typeof value === 'object' && 'Date' === value.type) {
+// return new Date(value.time);
+// } else {
+// return value;
+// }
+// }}.
+// If the reviver returns {@code undefined} then the property named by key
+// will be deleted from its container.
+// {@code this} is bound to the object containing the specified property.
+// returns: {Object|Array}
+(function () {
+ var number
+ = '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)';
+ var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]'
+ + '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))';
+ var string = '(?:\"' + oneChar + '*\")';
+
+ // Will match a value in a well-formed JSON file.
+ // If the input is not well-formed, may match strangely, but not in an unsafe
+ // way.
+ // Since this only matches value tokens, it does not match whitespace, colons,
+ // or commas.
+ var jsonToken = new RegExp(
+ '(?:false|true|null|[\\{\\}\\[\\]]'
+ + '|' + number
+ + '|' + string
+ + ')', 'g');
+
+ // Matches escape sequences in a string literal
+ var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g');
+
+ // Decodes escape sequences in object literals
+ var escapes = {
+ '"': '"',
+ '/': '/',
+ '\\': '\\',
+ 'b': '\b',
+ 'f': '\f',
+ 'n': '\n',
+ 'r': '\r',
+ 't': '\t'
+ };
+ function unescapeOne(_, ch, hex) {
+ return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16));
+ }
+
+ // A non-falsy value that coerces to the empty string when used as a key.
+ var EMPTY_STRING = new String('');
+ var SLASH = '\\';
+
+ // Constructor to use based on an open token.
+ var firstTokenCtors = { '{': Object, '[': Array };
+
+ var hop = Object.hasOwnProperty;
+
+ return function (json, opt_reviver) {
+ // Split into tokens
+ var toks = json.match(jsonToken);
+ // Construct the object to return
+ var result;
+ var tok = toks[0];
+ var topLevelPrimitive = false;
+ if ('{' === tok) {
+ result = {};
+ } else if ('[' === tok) {
+ result = [];
+ } else {
+ // The RFC only allows arrays or objects at the top level, but the JSON.parse
+ // defined by the EcmaScript 5 draft does allow strings, booleans, numbers, and null
+ // at the top level.
+ result = [];
+ topLevelPrimitive = true;
+ }
+
+ // If undefined, the key in an object key/value record to use for the next
+ // value parsed.
+ var key;
+ // Loop over remaining tokens maintaining a stack of uncompleted objects and
+ // arrays.
+ var stack = [result];
+ for (var i = 1 - topLevelPrimitive, n = toks.length; i < n; ++i) {
+ tok = toks[i];
+
+ var cont;
+ switch (tok.charCodeAt(0)) {
+ default: // sign or digit
+ cont = stack[0];
+ cont[key || cont.length] = +(tok);
+ key = void 0;
+ break;
+ case 0x22: // '"'
+ tok = tok.substring(1, tok.length - 1);
+ if (tok.indexOf(SLASH) !== -1) {
+ tok = tok.replace(escapeSequence, unescapeOne);
+ }
+ cont = stack[0];
+ if (!key) {
+ if (cont instanceof Array) {
+ key = cont.length;
+ } else {
+ key = tok || EMPTY_STRING; // Use as key for next value seen.
+ break;
+ }
+ }
+ cont[key] = tok;
+ key = void 0;
+ break;
+ case 0x5b: // '['
+ cont = stack[0];
+ stack.unshift(cont[key || cont.length] = []);
+ key = void 0;
+ break;
+ case 0x5d: // ']'
+ stack.shift();
+ break;
+ case 0x66: // 'f'
+ cont = stack[0];
+ cont[key || cont.length] = false;
+ key = void 0;
+ break;
+ case 0x6e: // 'n'
+ cont = stack[0];
+ cont[key || cont.length] = null;
+ key = void 0;
+ break;
+ case 0x74: // 't'
+ cont = stack[0];
+ cont[key || cont.length] = true;
+ key = void 0;
+ break;
+ case 0x7b: // '{'
+ cont = stack[0];
+ stack.unshift(cont[key || cont.length] = {});
+ key = void 0;
+ break;
+ case 0x7d: // '}'
+ stack.shift();
+ break;
+ }
+ }
+ // Fail if we've got an uncompleted object.
+ if (topLevelPrimitive) {
+ if (stack.length !== 1) { throw new Error(); }
+ result = result[0];
+ } else {
+ if (stack.length) { throw new Error(); }
+ }
+
+ if (opt_reviver) {
+ // Based on walk as implemented in http://www.json.org/json2.js
+ var walk = function (holder, key) {
+ var value = holder[key];
+ if (value && typeof value === 'object') {
+ var toDelete = null;
+ for (var k in value) {
+ if (hop.call(value, k) && value !== holder) {
+ // Recurse to properties first. This has the effect of causing
+ // the reviver to be called on the object graph depth-first.
+
+ // Since 'this' is bound to the holder of the property, the
+ // reviver can access sibling properties of k including ones
+ // that have not yet been revived.
+
+ // The value returned by the reviver is used in place of the
+ // current value of property k.
+ // If it returns undefined then the property is deleted.
+ var v = walk(value, k);
+ if (v !== void 0) {
+ value[k] = v;
+ } else {
+ // Deleting properties inside the loop has vaguely defined
+ // semantics in ES3 and ES3.1.
+ if (!toDelete) { toDelete = []; }
+ toDelete.push(k);
+ }
+ }
+ }
+ if (toDelete) {
+ for (var i = toDelete.length; --i >= 0;) {
+ delete value[toDelete[i]];
+ }
+ }
+ }
+ return opt_reviver.call(holder, key, value);
+ };
+ result = walk({ '': result }, '');
+ }
+
+ return result;
+ };
+})();
+});