Example #1
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 wchar_t** data Pointer to a wchar_t* that contains the JSON text
 * @param std::wstring& str Reference to a std::wstring to receive the extracted string
 *
 * @return bool Returns true on success, false on failure
 */
bool JSON::ExtractString(const wchar_t **data, std::wstring &str)
{
	str = L"";
	
	while (**data != 0)
	{
		// Save the char so we can change it if need be
		wchar_t next_char = **data;
		
		// Escaping something?
		if (next_char == L'\\')
		{
			// Move over the escape char
			(*data)++;
			
			// Deal with the escaped char
			switch (**data)
			{
				case L'"': next_char = L'"'; break;
				case L'\\': next_char = L'\\'; break;
				case L'/': next_char = L'/'; break;
				case L'b': next_char = L'\b'; break;
				case L'f': next_char = L'\f'; break;
				case L'n': next_char = L'\n'; break;
				case L'r': next_char = L'\r'; break;
				case L't': next_char = L'\t'; break;
				case L'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 == L'"')
		{
			(*data)++;
			str.reserve(); // Remove unused capacity
			return true;
		}
		
		// Disallowed char?
		else if (next_char < L' ' && next_char != L'\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;
}
Example #2
0
/**
 * Parses a JSON encoded value to a JSONValue object
 *
 * @access protected
 *
 * @param wchar_t** data Pointer to a wchar_t* that contains the data
 *
 * @return JSONValue* Returns a pointer to a JSONValue object on success, NULL on error
 */
JSONValue *JSONValue::Parse(const wchar_t **data)
{
    // Is it a string?
    if (**data == '"')
    {
        std::wstring str;
        if (!JSON::ExtractString(&(++(*data)), str))
            return NULL;
        else
            return new JSONValue(str);
    }

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

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

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

        double number = 0.0;

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

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

            // Not get any digits?
            if (!(**data >= L'0' && **data <= L'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;
        }

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

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

            // Not get any digits?
            if (!(**data >= L'0' && **data <= L'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);
        }

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

        return new JSONValue(number);
    }

    // An object?
    else if (**data == L'{')
    {
        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 == L'}')
            {
                (*data)++;
                return new JSONValue(object);
            }

            // We want a string now...
            std::wstring 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)++) != L':')
            {
                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 == L'}')
            {
                (*data)++;
                return new JSONValue(object);
            }

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

            (*data)++;
        }

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

    // An array?
    else if (**data == L'[')
    {
        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 == L']')
            {
                (*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 == L']')
            {
                (*data)++;
                return new JSONValue(array);
            }

            // Want a , now
            if (**data != L',')
            {
                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;
    }
}