/**
         * Attempts to read a number from the input string.  Places
         * the character location at the first character after the
         * number.
         *
         * @return The JSONToken with the number value if a number could
         *      be read.  Throws an error otherwise.
         */
        private JSONToken readNumber()
        {
            // the string to accumulate the number characters
            // into that we'll convert to a number at the end
            string input = "";

            // check for a negative number
            if (ch == '-')
            {
                input += '-';
                nextChar();
            }
            // the number must start with a digit
            if (!isDigit(ch))
            {
                parseError("Expecting a digit");
            }
            // 0 can only be the first digit if it
            // is followed by a decimal point
            if (ch == '0')
            {
                input += ch;
                nextChar();
                // make sure no other digits come after 0
                if (isDigit(ch))
                {
                    parseError("A digit cannot immediately follow 0");
                }
                // unless we have 0x which starts a hex number, but this
                // doesn't match JSON spec so check for not strict mode.
                else
                {
                    if (!strict && ch == 'x')
                    {
                        // include the x in the input
                        input += ch;
                        nextChar();
                        // need at least one hex digit after 0x to
                        // be valid
                        if (isHexDigit(ch))
                        {
                            input += ch;
                            nextChar();
                        }
                        else
                        {
                            parseError("Number in hex format require at least one hex digit after \"0x\"");
                        }
                        // consume all of the hex values
                        while (isHexDigit(ch))
                        {
                            input += ch;
                            nextChar();
                        }
                        input = Convert.ToInt32(input, 16).ToString();
                    }
                }
            }
            else
            {
                // read numbers while we can
                while (isDigit(ch))
                {
                    input += ch;
                    nextChar();
                }
            }
            // check for a decimal value
            if (ch == '.')
            {
                input += '.';
                nextChar();
                // after the decimal there has to be a digit
                if (!isDigit(ch))
                {
                    parseError("Expecting a digit");
                }
                // read more numbers to get the decimal value
                while (isDigit(ch))
                {
                    input += ch;
                    nextChar();
                }
            }
            // check for scientific notation
            if (ch == 'e' || ch == 'E')
            {
                input += "e";
                nextChar();
                // check for sign
                if (ch == '+' || ch == '-')
                {
                    input += ch;
                    nextChar();
                }
                // require at least one number for the exponent
                // in this case
                if (!isDigit(ch))
                {
                    parseError("Scientific notation number needs exponent value");
                }
                // read in the exponent
                while (isDigit(ch))
                {
                    input += ch;
                    nextChar();
                }
            }
            // convert the string to a number value
            int  int_num;
            bool correct_int = false;

            try
            {
                int_num     = Convert.ToInt32(input);
                correct_int = true;
            }
            catch (FormatException)
            {
                int_num     = 0;
                correct_int = false;
            }

            long long_num;
            bool correct_long = false;

            try
            {
                long_num     = Convert.ToInt64(input);
                correct_long = true;
            }
            catch (FormatException)
            {
                long_num     = 0;
                correct_long = false;
            }

            float float_num = Convert.ToSingle(input, CultureInfo.InvariantCulture);

            if (!float.IsInfinity(float_num) && !float.IsNaN(float_num))
            {
                // the token for the number we'll try to read
                JSONToken token = new JSONToken();
                token.type = JSONTokenType.NUMBER;

                if (correct_long && float_num == Convert.ToSingle(long_num)) // the number is integer
                {
                    if (correct_int && long_num == Convert.ToInt64(int_num)) // the number is int32
                    {
                        token.value = int_num;                               // boxing int to object
                    }
                    else                                                     // the number is int64
                    {
                        token.value = long_num;                              // boxing long int to object
                    }
                }
                else                  // the number is float
                {
                    token.value = float_num;
                }
                return(token);
            }
            else
            {
                parseError("Number " + float_num + " is not valid!");
            }
            return(null);
        }
        /**
         * Gets the next token in the input sting and advances
         * the character to the next character after the token
         */
        public JSONToken getNextToken()
        {
            JSONToken token = null;

            // skip any whitespace / comments since the last
            // token was read
            skipIgnored();
            // examine the new character and see what we have...
            switch (ch)
            {
            case '{':
                token = new JSONToken(JSONTokenType.LEFT_BRACE, '{');
                nextChar();
                break;

            case '}':
                token = new JSONToken(JSONTokenType.RIGHT_BRACE, '}');
                nextChar();
                break;

            case '[':
                token = new JSONToken(JSONTokenType.LEFT_BRACKET, '[');
                nextChar();
                break;

            case ']':
                token = new JSONToken(JSONTokenType.RIGHT_BRACKET, ']');
                nextChar();
                break;

            case ',':
                token = new JSONToken(JSONTokenType.COMMA, ',');
                nextChar();
                break;

            case ':':
                token = new JSONToken(JSONTokenType.COLON, ':');
                nextChar();
                break;

            case 't':                     // attempt to read true
                string possibleTrue = "t" + nextChar() + nextChar() + nextChar();
                if (possibleTrue == "true")
                {
                    token = new JSONToken(JSONTokenType.TRUE, true);
                    nextChar();
                }
                else
                {
                    parseError("Expecting 'true' but found " + possibleTrue);
                }
                break;

            case 'f':                     // attempt to read false
                string possibleFalse = "f" + nextChar() + nextChar() + nextChar() + nextChar();
                if (possibleFalse == "false")
                {
                    token = new JSONToken(JSONTokenType.FALSE, false);
                    nextChar();
                }
                else
                {
                    parseError("Expecting 'false' but found " + possibleFalse);
                }
                break;

            case 'n':                     // attempt to read null
                string possibleNull = "n" + nextChar() + nextChar() + nextChar();
                if (possibleNull == "null")
                {
                    token = new JSONToken(JSONTokenType.NULL, null);
                    nextChar();
                }
                else
                {
                    parseError("Expecting 'null' but found " + possibleNull);
                }
                break;

            case 'N':                     //attempt to read NAN
                string possibleNAN = "N" + nextChar() + nextChar();
                if (possibleNAN == "NAN" || possibleNAN == "NaN")
                {
                    token = new JSONToken(JSONTokenType.NAN, float.NaN);
                    nextChar();
                }
                else
                {
                    parseError("Expecting 'nan' but found " + possibleNAN);
                }
                break;

            case '"':                     // the start of a string
                token = readString();
                break;

            default:
                // see if we can read a number
                if (isDigit(ch) || ch == '-')
                {
                    token = readNumber();
                }
                else if (ch == 0)
                {
                    // check for reading past the end of the string
                    return(null);
                }
                else
                {
                    // not sure what was in the input string - it's not
                    // anything we expected
                    parseError("Unexpected " + ch + " encountered");
                }
                break;
            }
            return(token);
        }
        /**
         * Attempts to read a string from the input string.  Places
         * the character location at the first character after the
         * string.  It is assumed that ch is " before this method is called.
         *
         * @return the JSONToken with the string value if a string could
         *		be read.  Throws an error otherwise.
         */
        private JSONToken readString()
        {
            // the string to store the string we'll try to read
            string str = "";

            // advance past the first "
            nextChar();
            while (ch != '"' && ch != 0)
            {
                //trace(ch);
                // unescape the escape sequences in the string
                if (ch == '\\')
                {
                    // get the next character so we know what
                    // to unescape
                    nextChar();
                    switch (ch)
                    {
                    case '"':                             // quotation mark
                        str += '"';
                        break;

                    case '/':                                   // solidus
                        str += "/";
                        break;

                    case '\\':                                  // reverse solidus
                        str += '\\';
                        break;

                    case 'n':                                   // newline
                        str += '\n';
                        break;

                    case 'r':                                   // carriage return
                        str += '\r';
                        break;

                    case 't':                                   // horizontal tab
                        str += '\t';
                        break;

                    case 'u':
                        // convert a unicode escape sequence
                        // to it's character value - expecting
                        // 4 hex digits
                        // save the characters as a string we'll convert to an int
                        string hexValue = "";
                        // try to find 4 hex characters
                        for (int i = 0; i < 4; i++)
                        {
                            // get the next character and determine
                            // if it's a valid hex digit or not
                            if (!isHexDigit(nextChar()))
                            {
                                parseError(" Excepted a hex digit, but found: " + ch);
                            }
                            // valid, add it to the value
                            hexValue += ch;
                        }
                        // convert hexValue to an integer, and use that
                        // integrer value to create a character to add
                        // to our string.
                        str += ((char)Convert.ToInt32(hexValue, 16)).ToString();
                        break;

                    default:
                        // couldn't unescape the sequence, so just
                        // pass it through
                        str += '\\' + ch;
                        break;
                    }
                }
                else
                {
                    // didn't have to unescape, so add the character to the string
                    str += ch;
                }
                // move to the next character
                nextChar();
            }

            // we read past the end of the string without closing it, which
            // is a parse error
            if (ch == 0)
            {
                parseError("Unterminated string literal");
            }
            // move past the closing " in the input string
            nextChar();
            // the token for the string we'll try to read
            JSONToken token = new JSONToken();

            token.type = JSONTokenType.STRING;
            // attach to the string to the token so we can return it
            token.value = str;
            return(token);
        }
 private JSONToken nextToken()
 {
     return(token = tokenizer.getNextToken());
 }