Example #1
0
        private CBORObject NextJSONNonnegativeNumber(int c, int[] nextChar)
        {
            // Assumes the last character read was a digit
            CBORObject obj              = null;
            int        cval             = c - '0';
            int        cstart           = c;
            int        startIndex       = this.index - 1;
            var        needObj          = true;
            int        numberStartIndex = this.index - 1;

            // DebugUtility.Log("js=" + (jstring));
            c = this.index < this.endPos ? ((int)this.jstring[this.index++]) &
                0xffff : -1;
            if (!(c == '-' || c == '+' || c == '.' || (c >= '0' && c <= '9') ||
                  c == 'e' || c == 'E'))
            {
                // Optimize for common case where JSON number
                // is a single digit without sign or exponent
                obj     = CBORDataUtilities.ParseSmallNumber(cval, this.options);
                needObj = false;
            }
            else if (c >= '0' && c <= '9')
            {
                int csecond = c;
                if (cstart == '0')
                {
                    // Leading zero followed by any digit is not allowed
                    this.RaiseError("JSON number can't be parsed.");
                }
                cval = (cval * 10) + (int)(c - '0');
                c    = this.index < this.endPos ? ((int)this.jstring[this.index++]) : -1;
                if (c >= '0' && c <= '9')
                {
                    var digits = 2;
                    while (digits < 9 && (c >= '0' && c <= '9'))
                    {
                        cval = (cval * 10) + (int)(c - '0');
                        c    = this.index < this.endPos ?
                               ((int)this.jstring[this.index++]) : -1;
                        ++digits;
                    }
                    if (!(c == 'e' || c == 'E' || c == '.' || (c >= '0' && c <=
                                                               '9')))
                    {
                        // All-digit number that's short enough
                        obj     = CBORDataUtilities.ParseSmallNumber(cval, this.options);
                        needObj = false;
                    }
                }
                else if (!(c == '-' || c == '+' || c == '.' || c == 'e' || c
                           == 'E'))
                {
                    // Optimize for common case where JSON number
                    // is two digits without sign, decimal point, or exponent
                    obj     = CBORDataUtilities.ParseSmallNumber(cval, this.options);
                    needObj = false;
                }
            }
            if (needObj)
            {
                // NOTE: Differs from CBORJson2, notably because the whole
                // rest of the string is checked whether the beginning of the rest
                // is a JSON number
                var endIndex = new int[1];
                endIndex[0] = numberStartIndex;
                obj         = CBORDataUtilities.ParseJSONNumber(
                    this.jstring,
                    numberStartIndex,
                    this.endPos - numberStartIndex,
                    this.options,
                    endIndex);
                int numberEndIndex = endIndex[0];
                this.index = numberEndIndex >= this.endPos ? this.endPos :
                             (numberEndIndex + 1);
                if (obj == null)
                {
                    int    strlen = numberEndIndex - numberStartIndex;
                    string errstr = this.jstring.Substring(numberStartIndex,
                                                           Math.Min(100, strlen));
                    if (strlen > 100)
                    {
                        errstr += "...";
                    }
                    this.RaiseError("JSON number can't be parsed. " + errstr);
                }
#if DEBUG
                if (numberEndIndex < numberStartIndex)
                {
                    throw new ArgumentException("numberEndIndex (" + numberEndIndex +
                                                ") is not greater or equal to " + numberStartIndex);
                }
#endif

                c = numberEndIndex >= this.endPos ? -1 :
                    this.jstring[numberEndIndex];
                // check if character can validly appear after a JSON number
                if (c != ',' && c != ']' && c != '}' && c != -1 &&
                    c != 0x20 && c != 0x0a && c != 0x0d && c != 0x09)
                {
                    this.RaiseError("Invalid character after JSON number");
                }
                // DebugUtility.Log("endIndex="+endIndex[0]+", "+
                // this.jstring.Substring(endIndex[0],
                // Math.Min(20, this.endPos-endIndex[0])));
            }
            if (c == -1 || (c != 0x20 && c != 0x0a && c != 0x0d && c != 0x09))
            {
                nextChar[0] = c;
            }
            else
            {
                nextChar[0] = this.SkipWhitespaceJSON();
            }
            return(obj);
        }
Example #2
0
        private CBORObject NextJSONValue(
            int firstChar,
            int[] nextChar,
            int depth)
        {
            string     str;
            int        c   = firstChar;
            CBORObject obj = null;

            if (c < 0)
            {
                this.RaiseError("Unexpected end of data");
            }
            switch (c)
            {
            case '"': {
                // Parse a string
                // The tokenizer already checked the string for invalid
                // surrogate pairs, so just call the CBORObject
                // constructor directly
                obj         = CBORObject.FromRaw(this.NextJSONString());
                nextChar[0] = this.SkipWhitespaceJSON();
                return(obj);
            }

            case '{': {
                // Parse an object
                obj         = this.ParseJSONObject(depth + 1);
                nextChar[0] = this.SkipWhitespaceJSON();
                return(obj);
            }

            case '[': {
                // Parse an array
                obj         = this.ParseJSONArray(depth + 1);
                nextChar[0] = this.SkipWhitespaceJSON();
                return(obj);
            }

            case 't': {
                // Parse true
                if ((c = this.ReadChar()) != 'r' || (c = this.ReadChar()) != 'u' ||
                    (c = this.ReadChar()) != 'e')
                {
                    this.RaiseError("Value can't be parsed.");
                }
                c = this.ReadChar();
                if (c == 0x20 || c == 0x0a || c == 0x0d || c == 0x09)
                {
                    nextChar[0] = this.SkipWhitespaceJSON();
                }
                else if (this.jsonSequenceMode && depth == 0)
                {
                    nextChar[0] = c;
                    this.RaiseError("JSON whitespace expected after top-level " +
                                    "number in JSON sequence");
                }
                else
                {
                    nextChar[0] = c;
                }
                return(CBORObject.True);
            }

            case 'f': {
                // Parse false
                if ((c = this.ReadChar()) != 'a' || (c = this.ReadChar()) != 'l' ||
                    (c = this.ReadChar()) != 's' || (c = this.ReadChar()) != 'e')
                {
                    this.RaiseError("Value can't be parsed.");
                }
                c = this.ReadChar();
                if (c == 0x20 || c == 0x0a || c == 0x0d || c == 0x09)
                {
                    nextChar[0] = this.SkipWhitespaceJSON();
                }
                else if (this.jsonSequenceMode && depth == 0)
                {
                    nextChar[0] = c;
                    this.RaiseError("JSON whitespace expected after top-level " +
                                    "number in JSON sequence");
                }
                else
                {
                    nextChar[0] = c;
                }
                return(CBORObject.False);
            }

            case 'n': {
                // Parse null
                if ((c = this.ReadChar()) != 'u' || (c = this.ReadChar()) != 'l' ||
                    (c = this.ReadChar()) != 'l')
                {
                    this.RaiseError("Value can't be parsed.");
                }
                c = this.ReadChar();
                if (c == 0x20 || c == 0x0a || c == 0x0d || c == 0x09)
                {
                    nextChar[0] = this.SkipWhitespaceJSON();
                }
                else if (this.jsonSequenceMode && depth == 0)
                {
                    nextChar[0] = c;
                    this.RaiseError("JSON whitespace expected after top-level " +
                                    "number in JSON sequence");
                }
                else
                {
                    nextChar[0] = c;
                }
                return(CBORObject.Null);
            }

            case '-': {
                // Parse a negative number
                return(this.NextJSONNegativeNumber(nextChar, depth));
            }

            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9': {
                // Parse a nonnegative number
                int cval    = c - '0';
                int cstart  = c;
                var needObj = true;
                c = this.ReadChar();
                if (!(c == '-' || c == '+' || c == '.' || (c >= '0' && c <= '9') ||
                      c == 'e' || c == 'E'))
                {
                    // Optimize for common case where JSON number
                    // is a single digit without sign or exponent
                    obj     = CBORDataUtilities.ParseSmallNumber(cval, this.options);
                    needObj = false;
                }
                else if (c >= '0' && c <= '9')
                {
                    int csecond = c;
                    if (cstart == '0')
                    {
                        // Leading zero followed by any digit is not allowed
                        this.RaiseError("JSON number can't be parsed.");
                    }
                    cval = (cval * 10) + (int)(c - '0');
                    c    = this.ReadChar();
                    if (c >= '0' && c <= '9')
                    {
                        var digits = 2;
                        var ctmp   = new int[10];
                        ctmp[0] = cstart;
                        ctmp[1] = csecond;
                        while (digits < 9 && (c >= '0' && c <= '9'))
                        {
                            cval           = (cval * 10) + (int)(c - '0');
                            ctmp[digits++] = c;
                            c = this.ReadChar();
                        }
                        if (c == 'e' || c == 'E' || c == '.' || (c >= '0' && c <= '9'))
                        {
                            // Not an all-digit number, or too long
                            this.sb = this.sb ?? new StringBuilder();
                            this.sb.Remove(0, this.sb.Length);
                            for (var vi = 0; vi < digits; ++vi)
                            {
                                this.sb.Append((char)ctmp[vi]);
                            }
                        }
                        else
                        {
                            obj     = CBORDataUtilities.ParseSmallNumber(cval, this.options);
                            needObj = false;
                        }
                    }
                    else if (!(c == '-' || c == '+' || c == '.' || c == 'e' || c
                               == 'E'))
                    {
                        // Optimize for common case where JSON number
                        // is two digits without sign, decimal point, or exponent
                        obj     = CBORDataUtilities.ParseSmallNumber(cval, this.options);
                        needObj = false;
                    }
                    else
                    {
                        this.sb = this.sb ?? new StringBuilder();
                        this.sb.Remove(0, this.sb.Length);
                        this.sb.Append((char)cstart);
                        this.sb.Append((char)csecond);
                    }
                }
                else
                {
                    this.sb = this.sb ?? new StringBuilder();
                    this.sb.Remove(0, this.sb.Length);
                    this.sb.Append((char)cstart);
                }
                if (needObj)
                {
                    var charbuf    = new char[32];
                    var charbufptr = 0;
                    while (
                        c == '-' || c == '+' || c == '.' || (c >= '0' && c <= '9') ||
                        c == 'e' || c == 'E')
                    {
                        charbuf[charbufptr++] = (char)c;
                        if (charbufptr >= 32)
                        {
                            this.sb.Append(charbuf, 0, 32);
                            charbufptr = 0;
                        }
                        c = this.ReadChar();
                    }
                    if (charbufptr > 0)
                    {
                        this.sb.Append(charbuf, 0, charbufptr);
                    }
                    // check if character can validly appear after a JSON number
                    if (c != ',' && c != ']' && c != '}' && c != -1 &&
                        c != 0x20 && c != 0x0a && c != 0x0d && c != 0x09)
                    {
                        this.RaiseError("Invalid character after JSON number");
                    }
                    str = this.sb.ToString();
                    obj = CBORDataUtilities.ParseJSONNumber(str, this.options);
                    if (obj == null)
                    {
                        string errstr = (str.Length <= 100) ? str : (str.Substring(0,
                                                                                   100) + "...");
                        this.RaiseError("JSON number can't be parsed. " + errstr);
                    }
                }
                if (c == 0x20 || c == 0x0a || c == 0x0d || c == 0x09)
                {
                    nextChar[0] = this.SkipWhitespaceJSON();
                }
                else if (this.jsonSequenceMode && depth == 0)
                {
                    nextChar[0] = c;
                    this.RaiseError("JSON whitespace expected after top-level " +
                                    "number in JSON sequence");
                }
                else
                {
                    nextChar[0] = c;
                }
                return(obj);
            }

            default: this.RaiseError("Value can't be parsed.");
                break;
            }
            return(null);
        }