﻿/*
* jQuery JSON Plugin
* version: 1.0 (2008-04-17)
*
* This document is licensed as free software under the terms of the
* MIT License: http://www.opensource.org/licenses/mit-license.php
*
* Brantley Harris technically wrote this plugin, but it is based somewhat
* on the JSON.org website's http://www.json.org/json2.js, which proclaims:
* "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
* I uphold.  I really just cleaned it up.
*
* It is also based heavily on MochiKit's serializeJSON, which is 
* copywrited 2005 by Bob Ippolito.
*/

(function($)
{
	function toIntegersAtLease(n)
	// Format integers to have at least two digits.
	{
		return n < 10 ? '0' + n : n;
	}

	Date.prototype.toJSON = function(date)
	// Yes, it polutes the Date namespace, but we'll allow it here, as
	// it's damned usefull.
	{
		return this.getUTCFullYear() + '-' +
			 toIntegersAtLease(this.getUTCMonth()) + '-' +
			 toIntegersAtLease(this.getUTCDate());
	};

	var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
	var meta = {    // table of character substitutions
		'\b': '\\b',
		'\t': '\\t',
		'\n': '\\n',
		'\f': '\\f',
		'\r': '\\r',
		'"': '\\"',
		'\\': '\\\\'
	};

	$.quoteString = function(string)
	// Places quotes around a string, inteligently.
	// If the string contains no control characters, no quote characters, and no
	// backslash characters, then we can safely slap some quotes around it.
	// Otherwise we must also replace the offending characters with safe escape
	// sequences.
	{
		if (escapeable.test(string))
		{
			return '"' + string.replace(escapeable, function(a)
			{
				var c = meta[a];
				if (typeof c === 'string')
				{
					return c;
				}
				c = a.charCodeAt();
				return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
			}) + '"';
		}
		return '"' + string + '"';
	};

	$.toJSON = function(o, compact)
	{
		var type = typeof (o);

		if (type == "undefined")
			return "undefined";
		else if (type == "number" || type == "boolean")
			return o + "";
		else if (o === null)
			return "null";

		// Is it a string?
		if (type == "string")
		{
			return $.quoteString(o);
		}

		// Does it have a .toJSON function?
		if (type == "object" && typeof o.toJSON == "function")
			return o.toJSON(compact);

		// Is it an array?
		if (type != "function" && typeof (o.length) == "number")
		{
			var ret = [];
			for (var i = 0; i < o.length; i++)
			{
				ret.push($.toJSON(o[i], compact));
			}
			if (compact)
				return "[" + ret.join(",") + "]";
			else
				return "[" + ret.join(", ") + "]";
		}

		// If it's a function, we have to warn somebody!
		if (type == "function")
		{
			throw new TypeError("Unable to convert object of type 'function' to json.");
		}

		// It's probably an object, then.
		var ret = [];
		for (var k in o)
		{
			var name;
			type = typeof (k);

			if (type == "number")
				name = '"' + k + '"';
			else if (type == "string")
				name = $.quoteString(k);
			else
				continue;  //skip non-string or number keys

			var val = $.toJSON(o[k], compact);
			if (typeof (val) != "string")
			{
				// skip non-serializable values
				continue;
			}

			if (compact)
				ret.push(name + ":" + val);
			else
				ret.push(name + ": " + val);
		}
		return "{" + ret.join(", ") + "}";
	};

	$.compactJSON = function(o)
	{
		return $.toJSON(o, true);
	};

	$.evalJSON = function(src)
	// Evals JSON that we know to be safe.
	{
		return eval("(" + src + ")");
	};

	$.secureEvalJSON = function(src)
	// Evals JSON in a way that is *more* secure.
	{
		var filtered = src;
		filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
		filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
		filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');

		if (/^[\],:{}\s]*$/.test(filtered))
			return eval("(" + src + ")");
		else
			throw new SyntaxError("Error parsing JSON, source is not valid.");
	};
})(jQuery);

