/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

/*
 * Files JSON.cpp and JSONValue.cpp part of the SimpleJSON Library - https://github.com/MJPA/SimpleJSON
 *
 * Copyright (C) 2010 Mike Anchor
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "common/json.h"

#ifdef __MINGW32__
#define wcsncasecmp wcsnicmp
#endif

// Macros to free an array/object
#define FREE_ARRAY(x) { JSONArray::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete *iter; } }
#define FREE_OBJECT(x) { JSONObject::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete (*iter)._value; } }

namespace Common {

/**
* Blocks off the public constructor
*
* @access private
*
*/
JSON::JSON() {}

/**
* Parses a complete JSON encoded string (UNICODE input version)
*
* @access public
*
* @param char* data The JSON text
*
* @return JSONValue* Returns a JSON Value representing the root, or NULL on error
*/
JSONValue *JSON::parse(const char *data) {
	// Skip any preceding whitespace, end of data = no JSON = fail
	if (!skipWhitespace(&data))
		return NULL;

	// We need the start of a value here now...
	JSONValue *value = JSONValue::parse(&data);
	if (value == NULL)
		return NULL;

	// Can be white space now and should be at the end of the string then...
	if (skipWhitespace(&data)) {
		delete value;
		return NULL;
	}

	// We're now at the end of the string
	return value;
}

/**
* Turns the passed in JSONValue into a JSON encode string
*
* @access public
*
* @param JSONValue* value The root value
*
* @return String Returns a JSON encoded string representation of the given value
*/
String JSON::stringify(const JSONValue *value) {
	if (value != NULL)
		return value->stringify();
	else
		return "";
}

/**
* Skips over any whitespace characters (space, tab, \r or \n) defined by the JSON spec
*
* @access protected
*
* @param char** data Pointer to a char* that contains the JSON text
*
* @return bool Returns true if there is more data, or false if the end of the text was reached
*/
bool JSON::skipWhitespace(const char **data) {
	while (**data != 0 && (**data == ' ' || **data == '\t' || **data == '\r' || **data == '\n'))
		(*data)++;

	return **data != 0;
}

/**
* Extracts a JSON String as defined by the spec - "<some chars>"
* Any escaped characters are swapped out for their unescaped values
*
* @access protected
*
* @param char** data Pointer to a char* that contains the JSON text
* @param String& str Reference to a String to receive the extracted string
*
* @return bool Returns true on success, false on failure
*/
bool JSON::extractString(const char **data, String &str) {
	str = "";

	while (**data != 0) {
		// Save the char so we can change it if need be
		char next_char = **data;

		// Escaping something?
		if (next_char == '\\') {
			// Move over the escape char
			(*data)++;

			// Deal with the escaped char
			switch (**data) {
			case '"': next_char = '"';
				break;
			case '\\': next_char = '\\';
				break;
			case '/': next_char = '/';
				break;
			case 'b': next_char = '\b';
				break;
			case 'f': next_char = '\f';
				break;
			case 'n': next_char = '\n';
				break;
			case 'r': next_char = '\r';
				break;
			case 't': next_char = '\t';
				break;
			case 'u': {
				// We need 5 chars (4 hex + the 'u') or its not valid
				if (!simplejson_wcsnlen(*data, 5))
					return false;

				// Deal with the chars
				next_char = 0;
				for (int i = 0; i < 4; i++) {
					// Do it first to move off the 'u' and leave us on the
					// final hex digit as we move on by one later on
					(*data)++;

					next_char <<= 4;

					// Parse the hex digit
					if (**data >= '0' && **data <= '9')
						next_char |= (**data - '0');
					else if (**data >= 'A' && **data <= 'F')
						next_char |= (10 + (**data - 'A'));
					else if (**data >= 'a' && **data <= 'f')
						next_char |= (10 + (**data - 'a'));
					else {
						// Invalid hex digit = invalid JSON
						return false;
					}
				}
				break;
			}

				// By the spec, only the above cases are allowed
			default:
				return false;
			}
		}

		// End of the string?
		else if (next_char == '"') {
			(*data)++;
			//str.reserve(); // Remove unused capacity //TODO
			return true;
		}

		// Disallowed char?
		else if (next_char < ' ' && next_char != '\t') {
			// SPEC Violation: Allow tabs due to real world cases
			return false;
		}

		// Add the next char
		str += next_char;

		// Move on
		(*data)++;
	}

	// If we're here, the string ended incorrectly
	return false;
}

/**
* Parses some text as though it is an integer
*
* @access protected
*
* @param char** data Pointer to a char* that contains the JSON text
*
* @return double Returns the double value of the number found
*/
double JSON::parseInt(const char **data) {
	double integer = 0;
	while (**data != 0 && **data >= '0' && **data <= '9')
		integer = integer * 10 + (*(*data)++ - '0');

	return integer;
}

/**
* Parses some text as though it is a decimal
*
* @access protected
*
* @param char** data Pointer to a char* that contains the JSON text
*
* @return double Returns the double value of the decimal found
*/
double JSON::parseDecimal(const char **data) {
	double decimal = 0.0;
	double factor = 0.1;
	while (**data != 0 && **data >= '0' && **data <= '9') {
		int digit = (*(*data)++ - '0');
		decimal = decimal + digit * factor;
		factor *= 0.1;
	}
	return decimal;
}

/**
* Parses a JSON encoded value to a JSONValue object
*
* @access protected
*
* @param char** data Pointer to a char* that contains the data
*
* @return JSONValue* Returns a pointer to a JSONValue object on success, NULL on error
*/
JSONValue *JSONValue::parse(const char **data) {
	// Is it a string?
	if (**data == '"') {
		String str;
		if (!JSON::extractString(&(++(*data)), str))
			return NULL;
		else
			return new JSONValue(str);
	}

	// Is it a boolean?
	else if ((simplejson_wcsnlen(*data, 4) && scumm_strnicmp(*data, "true", 4) == 0) || (simplejson_wcsnlen(*data, 5) && scumm_strnicmp(*data, "false", 5) == 0)) {
		bool value = scumm_strnicmp(*data, "true", 4) == 0;
		(*data) += value ? 4 : 5;
		return new JSONValue(value);
	}

	// Is it a null?
	else if (simplejson_wcsnlen(*data, 4) && scumm_strnicmp(*data, "null", 4) == 0) {
		(*data) += 4;
		return new JSONValue();
	}

	// Is it a number?
	else if (**data == '-' || (**data >= '0' && **data <= '9')) {
		// Negative?
		bool neg = **data == '-';
		if (neg) (*data)++;

		long long int integer = 0;
		double number = 0.0;
		bool onlyInteger = true;

		// Parse the whole part of the number - only if it wasn't 0
		if (**data == '0')
			(*data)++;
		else if (**data >= '1' && **data <= '9')
			number = integer = JSON::parseInt(data);
		else
			return NULL;

		// Could be a decimal now...
		if (**data == '.') {
			(*data)++;

			// Not get any digits?
			if (!(**data >= '0' && **data <= '9'))
				return NULL;

			// Find the decimal and sort the decimal place out
			// Use ParseDecimal as ParseInt won't work with decimals less than 0.1
			// thanks to Javier Abadia for the report & fix
			double decimal = JSON::parseDecimal(data);

			// Save the number
			number += decimal;
			onlyInteger = false;
		}

		// Could be an exponent now...
		if (**data == 'E' || **data == 'e') {
			(*data)++;

			// Check signage of expo
			bool neg_expo = false;
			if (**data == '-' || **data == '+') {
				neg_expo = **data == '-';
				(*data)++;
			}

			// Not get any digits?
			if (!(**data >= '0' && **data <= '9'))
				return NULL;

			// Sort the expo out
			double expo = JSON::parseInt(data);
			for (double i = 0.0; i < expo; i++)
				number = neg_expo ? (number / 10.0) : (number * 10.0);
			onlyInteger = false;
		}

		// Was it neg?
		if (neg) number *= -1;

		if (onlyInteger)
			return new JSONValue(neg ? -integer : integer);

		return new JSONValue(number);
	}

	// An object?
	else if (**data == '{') {
		JSONObject object;

		(*data)++;

		while (**data != 0) {
			// Whitespace at the start?
			if (!JSON::skipWhitespace(data)) {
				FREE_OBJECT(object);
				return NULL;
			}

			// Special case - empty object
			if (object.size() == 0 && **data == '}') {
				(*data)++;
				return new JSONValue(object);
			}

			// We want a string now...
			String name;
			if (!JSON::extractString(&(++(*data)), name)) {
				FREE_OBJECT(object);
				return NULL;
			}

			// More whitespace?
			if (!JSON::skipWhitespace(data)) {
				FREE_OBJECT(object);
				return NULL;
			}

			// Need a : now
			if (*((*data)++) != ':') {
				FREE_OBJECT(object);
				return NULL;
			}

			// More whitespace?
			if (!JSON::skipWhitespace(data)) {
				FREE_OBJECT(object);
				return NULL;
			}

			// The value is here
			JSONValue *value = parse(data);
			if (value == NULL) {
				FREE_OBJECT(object);
				return NULL;
			}

			// Add the name:value
			if (object.find(name) != object.end())
				delete object[name];
			object[name] = value;

			// More whitespace?
			if (!JSON::skipWhitespace(data)) {
				FREE_OBJECT(object);
				return NULL;
			}

			// End of object?
			if (**data == '}') {
				(*data)++;
				return new JSONValue(object);
			}

			// Want a , now
			if (**data != ',') {
				FREE_OBJECT(object);
				return NULL;
			}

			(*data)++;
		}

		// Only here if we ran out of data
		FREE_OBJECT(object);
		return NULL;
	}

	// An array?
	else if (**data == '[') {
		JSONArray array;

		(*data)++;

		while (**data != 0) {
			// Whitespace at the start?
			if (!JSON::skipWhitespace(data)) {
				FREE_ARRAY(array);
				return NULL;
			}

			// Special case - empty array
			if (array.size() == 0 && **data == ']') {
				(*data)++;
				return new JSONValue(array);
			}

			// Get the value
			JSONValue *value = parse(data);
			if (value == NULL) {
				FREE_ARRAY(array);
				return NULL;
			}

			// Add the value
			array.push_back(value);

			// More whitespace?
			if (!JSON::skipWhitespace(data)) {
				FREE_ARRAY(array);
				return NULL;
			}

			// End of array?
			if (**data == ']') {
				(*data)++;
				return new JSONValue(array);
			}

			// Want a , now
			if (**data != ',') {
				FREE_ARRAY(array);
				return NULL;
			}

			(*data)++;
		}

		// Only here if we ran out of data
		FREE_ARRAY(array);
		return NULL;
	}

	// Ran out of possibilites, it's bad!
	else {
		return NULL;
	}
}

/**
* Basic constructor for creating a JSON Value of type NULL
*
* @access public
*/
JSONValue::JSONValue(/*NULL*/) {
	_type = JSONType_Null;
}

/**
* Basic constructor for creating a JSON Value of type String
*
* @access public
*
* @param char* m_char_value The string to use as the value
*/
JSONValue::JSONValue(const char *charValue) {
	_type = JSONType_String;
	_stringValue = new String(String(charValue));
}

/**
* Basic constructor for creating a JSON Value of type String
*
* @access public
*
* @param String m_string_value The string to use as the value
*/
JSONValue::JSONValue(const String &stringValue) {
	_type = JSONType_String;
	_stringValue = new String(stringValue);
}

/**
* Basic constructor for creating a JSON Value of type Bool
*
* @access public
*
* @param bool m_bool_value The bool to use as the value
*/
JSONValue::JSONValue(bool boolValue) {
	_type = JSONType_Bool;
	_boolValue = boolValue;
}

/**
* Basic constructor for creating a JSON Value of type Number
*
* @access public
*
* @param double m_number_value The number to use as the value
*/
JSONValue::JSONValue(double numberValue) {
	_type = JSONType_Number;
	_numberValue = numberValue;
}

/**
* Basic constructor for creating a JSON Value of type Number (Integer)
*
* @access public
*
* @param int numberValue The number to use as the value
*/
JSONValue::JSONValue(long long int numberValue) {
	_type = JSONType_IntegerNumber;
	_integerValue = numberValue;
}

/**
* Basic constructor for creating a JSON Value of type Array
*
* @access public
*
* @param JSONArray m_array_value The JSONArray to use as the value
*/
JSONValue::JSONValue(const JSONArray &arrayValue) {
	_type = JSONType_Array;
	_arrayValue = new JSONArray(arrayValue);
}

/**
* Basic constructor for creating a JSON Value of type Object
*
* @access public
*
* @param JSONObject m_object_value The JSONObject to use as the value
*/
JSONValue::JSONValue(const JSONObject &objectValue) {
	_type = JSONType_Object;
	_objectValue = new JSONObject(objectValue);
}

/**
* Copy constructor to perform a deep copy of array / object values
*
* @access public
*
* @param JSONValue m_source The source JSONValue that is being copied
*/
JSONValue::JSONValue(const JSONValue &source) {
	_type = source._type;

	switch (_type) {
	case JSONType_String:
		_stringValue = new String(*source._stringValue);
		break;

	case JSONType_Bool:
		_boolValue = source._boolValue;
		break;

	case JSONType_Number:
		_numberValue = source._numberValue;
		break;

	case JSONType_IntegerNumber:
		_integerValue = source._integerValue;
		break;

	case JSONType_Array: {
		JSONArray source_array = *source._arrayValue;
		JSONArray::iterator iter;
		_arrayValue = new JSONArray();
		for (iter = source_array.begin(); iter != source_array.end(); iter++)
			_arrayValue->push_back(new JSONValue(**iter));
		break;
	}

	case JSONType_Object: {
		JSONObject source_object = *source._objectValue;
		_objectValue = new JSONObject();
		JSONObject::iterator iter;
		for (iter = source_object.begin(); iter != source_object.end(); iter++) {
			String name = (*iter)._key;
			(*_objectValue)[name] = new JSONValue(*((*iter)._value));
		}
		break;
	}

	case JSONType_Null:
		// Nothing to do.
		break;
	}
}

/**
* The destructor for the JSON Value object
* Handles deleting the objects in the array or the object value
*
* @access public
*/
JSONValue::~JSONValue() {
	if (_type == JSONType_Array) {
		JSONArray::iterator iter;
		for (iter = _arrayValue->begin(); iter != _arrayValue->end(); iter++)
			delete *iter;
		delete _arrayValue;
	} else if (_type == JSONType_Object) {
		JSONObject::iterator iter;
		for (iter = _objectValue->begin(); iter != _objectValue->end(); iter++) {
			delete (*iter)._value;
		}
		delete _objectValue;
	} else if (_type == JSONType_String) {
		delete _stringValue;
	}
}

/**
* Checks if the value is a NULL
*
* @access public
*
* @return bool Returns true if it is a NULL value, false otherwise
*/
bool JSONValue::isNull() const {
	return _type == JSONType_Null;
}

/**
* Checks if the value is a String
*
* @access public
*
* @return bool Returns true if it is a String value, false otherwise
*/
bool JSONValue::isString() const {
	return _type == JSONType_String;
}

/**
* Checks if the value is a Bool
*
* @access public
*
* @return bool Returns true if it is a Bool value, false otherwise
*/
bool JSONValue::isBool() const {
	return _type == JSONType_Bool;
}

/**
* Checks if the value is a Number
*
* @access public
*
* @return bool Returns true if it is a Number value, false otherwise
*/
bool JSONValue::isNumber() const {
	return _type == JSONType_Number;
}

/**
* Checks if the value is an Integer
*
* @access public
*
* @return bool Returns true if it is an Integer value, false otherwise
*/
bool JSONValue::isIntegerNumber() const {
	return _type == JSONType_IntegerNumber;
}

/**
* Checks if the value is an Array
*
* @access public
*
* @return bool Returns true if it is an Array value, false otherwise
*/
bool JSONValue::isArray() const {
	return _type == JSONType_Array;
}

/**
* Checks if the value is an Object
*
* @access public
*
* @return bool Returns true if it is an Object value, false otherwise
*/
bool JSONValue::isObject() const {
	return _type == JSONType_Object;
}

/**
* Retrieves the String value of this JSONValue
* Use isString() before using this method.
*
* @access public
*
* @return String Returns the string value
*/
const String &JSONValue::asString() const {
	return (*_stringValue);
}

/**
* Retrieves the Bool value of this JSONValue
* Use isBool() before using this method.
*
* @access public
*
* @return bool Returns the bool value
*/
bool JSONValue::asBool() const {
	return _boolValue;
}

/**
* Retrieves the Number value of this JSONValue
* Use isNumber() before using this method.
*
* @access public
*
* @return double Returns the number value
*/
double JSONValue::asNumber() const {
	return _numberValue;
}

/**
* Retrieves the Integer value of this JSONValue
* Use isIntegerNumber() before using this method.
*
* @access public
*
* @return int Returns the number value
*/
long long int JSONValue::asIntegerNumber() const {
	return _integerValue;
}

/**
* Retrieves the Array value of this JSONValue
* Use isArray() before using this method.
*
* @access public
*
* @return JSONArray Returns the array value
*/
const JSONArray &JSONValue::asArray() const {
	return (*_arrayValue);
}

/**
* Retrieves the Object value of this JSONValue
* Use isObject() before using this method.
*
* @access public
*
* @return JSONObject Returns the object value
*/
const JSONObject &JSONValue::asObject() const {
	return (*_objectValue);
}

/**
* Retrieves the number of children of this JSONValue.
* This number will be 0 or the actual number of children
* if isArray() or isObject().
*
* @access public
*
* @return The number of children.
*/
std::size_t JSONValue::countChildren() const {
	switch (_type) {
	case JSONType_Array:
		return _arrayValue->size();
	case JSONType_Object:
		return _objectValue->size();
	default:
		return 0;
	}
}

/**
* Checks if this JSONValue has a child at the given index.
* Use isArray() before using this method.
*
* @access public
*
* @return bool Returns true if the array has a value at the given index.
*/
bool JSONValue::hasChild(std::size_t index) const {
	if (_type == JSONType_Array) {
		return index < _arrayValue->size();
	} else {
		return false;
	}
}

/**
* Retrieves the child of this JSONValue at the given index.
* Use isArray() before using this method.
*
* @access public
*
* @return JSONValue* Returns JSONValue at the given index or NULL
*                    if it doesn't exist.
*/
JSONValue *JSONValue::child(std::size_t index) {
	if (index < _arrayValue->size()) {
		return (*_arrayValue)[index];
	} else {
		return NULL;
	}
}

/**
* Checks if this JSONValue has a child at the given key.
* Use isObject() before using this method.
*
* @access public
*
* @return bool Returns true if the object has a value at the given key.
*/
bool JSONValue::hasChild(const char *name) const {
	if (_type == JSONType_Object) {
		return _objectValue->find(name) != _objectValue->end();
	} else {
		return false;
	}
}

/**
* Retrieves the child of this JSONValue at the given key.
* Use isObject() before using this method.
*
* @access public
*
* @return JSONValue* Returns JSONValue for the given key in the object
*                    or NULL if it doesn't exist.
*/
JSONValue *JSONValue::child(const char *name) {
	JSONObject::const_iterator it = _objectValue->find(name);
	if (it != _objectValue->end()) {
		return it->_value;
	} else {
		return NULL;
	}
}

/**
* Retrieves the keys of the JSON Object or an empty vector
* if this value is not an object.
*
* @access public
*
* @return std::vector<String> A vector containing the keys.
*/
Array<String> JSONValue::objectKeys() const {
	Array<String> keys;

	if (_type == JSONType_Object) {
		JSONObject::const_iterator iter = _objectValue->begin();
		while (iter != _objectValue->end()) {
			keys.push_back(iter->_key);

			iter++;
		}
	}

	return keys;
}

/**
* Creates a JSON encoded string for the value with all necessary characters escaped
*
* @access public
*
* @param bool prettyprint Enable prettyprint
*
* @return String Returns the JSON string
*/
String JSONValue::stringify(bool const prettyprint) const {
	size_t const indentDepth = prettyprint ? 1 : 0;
	return stringifyImpl(indentDepth);
}


/**
* Creates a JSON encoded string for the value with all necessary characters escaped
*
* @access private
*
* @param size_t indentDepth The prettyprint indentation depth (0 : no prettyprint)
*
* @return String Returns the JSON string
*/
String JSONValue::stringifyImpl(size_t const indentDepth) const {
	String ret_string;
	size_t const indentDepth1 = indentDepth ? indentDepth + 1 : 0;
	String const indentStr = indent(indentDepth);
	String const indentStr1 = indent(indentDepth1);

	switch (_type) {
	case JSONType_Null:
		ret_string = "null";
		break;

	case JSONType_String:
		ret_string = stringifyString(*_stringValue);
		break;

	case JSONType_Bool:
		ret_string = _boolValue ? "true" : "false";
		break;

	case JSONType_Number: {
		if (isinf(_numberValue) || isnan(_numberValue))
			ret_string = "null";
		else {
			ret_string = String::format("%g", _numberValue);
		}
		break;
	}

	case JSONType_IntegerNumber: {
		ret_string = String::format("%lld", _integerValue);
		break;
	}

	case JSONType_Array: {
		ret_string = indentDepth ? "[\n" + indentStr1 : "[";
		JSONArray::const_iterator iter = _arrayValue->begin();
		while (iter != _arrayValue->end()) {
			ret_string += (*iter)->stringifyImpl(indentDepth1);

			// Not at the end - add a separator
			if (++iter != _arrayValue->end())
				ret_string += ",";
		}
		ret_string += indentDepth ? "\n" + indentStr + "]" : "]";
		break;
	}

	case JSONType_Object: {
		ret_string = indentDepth ? "{\n" + indentStr1 : "{";
		JSONObject::const_iterator iter = _objectValue->begin();
		while (iter != _objectValue->end()) {
			ret_string += stringifyString((*iter)._key);
			ret_string += ":";
			ret_string += (*iter)._value->stringifyImpl(indentDepth1);

			// Not at the end - add a separator
			if (++iter != _objectValue->end())
				ret_string += ",";
		}
		ret_string += indentDepth ? "\n" + indentStr + "}" : "}";
		break;
	}
	}

	return ret_string;
}

/**
* Creates a JSON encoded string with all required fields escaped
* Works from http://www.ecma-internationl.org/publications/files/ECMA-ST/ECMA-262.pdf
* Section 15.12.3.
*
* @access private
*
* @param String str The string that needs to have the characters escaped
*
* @return String Returns the JSON string
*/
String JSONValue::stringifyString(const String &str) {
	String str_out = "\"";

	String::const_iterator iter = str.begin();
	while (iter != str.end()) {
		char chr = *iter;

		if (chr == '"' || chr == '\\' || chr == '/') {
			str_out += '\\';
			str_out += chr;
		} else if (chr == '\b') {
			str_out += "\\b";
		} else if (chr == '\f') {
			str_out += "\\f";
		} else if (chr == '\n') {
			str_out += "\\n";
		} else if (chr == '\r') {
			str_out += "\\r";
		} else if (chr == '\t') {
			str_out += "\\t";
		} else if (chr < ' ' || chr > 126) {
			str_out += "\\u";
			for (int i = 0; i < 4; i++) {
				int value = (chr >> 12) & 0xf;
				if (value >= 0 && value <= 9)
					str_out += (char)('0' + value);
				else if (value >= 10 && value <= 15)
					str_out += (char)('A' + (value - 10));
				chr <<= 4;
			}
		} else {
			str_out += chr;
		}

		iter++;
	}

	str_out += "\"";
	return str_out;
}

/**
* Creates the indentation string for the depth given
*
* @access private
*
* @param size_t indent The prettyprint indentation depth (0 : no indentation)
*
* @return String Returns the string
*/
String JSONValue::indent(size_t depth) {
	const size_t indent_step = 2;
	depth ? --depth : 0;
	String indentStr;
	for (size_t i = 0; i < depth * indent_step; ++i) indentStr += ' ';
	return indentStr;
}

} // End of namespace Common
