/// <summary>Parses a number whose format follows the JSON /// specification (RFC 8259) and converts that number to a CBOR /// object.</summary> /// <param name='str'>A text string to parse as a JSON number.</param> /// <param name='offset'>An index, starting at 0, showing where the /// desired portion of <paramref name='str'/> begins.</param> /// <param name='count'>The length, in code units, of the desired /// portion of <paramref name='str'/> (but not more than <paramref /// name='str'/> 's length).</param> /// <param name='options'>An object containing options to control how /// JSON numbers are decoded to CBOR objects. Can be null, in which /// case a JSONOptions object with all default properties is used /// instead.</param> /// <returns>A CBOR object that represents the parsed number. Returns /// null if the parsing fails, including if the string is null or empty /// or <paramref name='count'/> is 0 or less.</returns> /// <exception cref='ArgumentNullException'>The parameter <paramref /// name='str'/> is null.</exception> /// <exception cref='ArgumentException'>Unsupported conversion /// kind.</exception> /// <remarks>Roughly speaking, a valid JSON number consists of an /// optional minus sign, one or more basic digits (starting with 1 to 9 /// unless there is only one digit and that digit is 0), an optional /// decimal point (".", full stop) with one or more basic digits, and /// an optional letter E or e with an optional plus or minus sign and /// one or more basic digits (the exponent). A text string representing /// a valid JSON number is not allowed to contain white space /// characters, including spaces.</remarks> public static CBORObject ParseJSONNumber( string str, int offset, int count, JSONOptions options) { return(CBORDataUtilitiesTextString.ParseJSONNumber( str, offset, count, options, null)); }
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 = CBORDataUtilitiesTextString.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); }
private CBORObject NextJSONNegativeNumber( int[] nextChar) { // Assumes the last character read was '-' // DebugUtility.Log("js=" + (jstring)); CBORObject obj; int numberStartIndex = this.index - 1; int c = this.index < this.endPos ? ((int)this.jstring[this.index++]) & 0xffff : -1; if (c < '0' || c > '9') { this.RaiseError("JSON number can't be parsed."); } if (this.index < this.endPos && c != '0') { // Check for negative single-digit int c2 = ((int)this.jstring[this.index]) & 0xffff; if (c2 == ',' || c2 == ']' || c2 == '}') { ++this.index; obj = CBORDataUtilities.ParseSmallNumberAsNegative( c - '0', this.options); nextChar[0] = c2; return(obj); } else if (c2 == 0x20 || c2 == 0x0a || c2 == 0x0d || c2 == 0x09) { ++this.index; obj = CBORDataUtilities.ParseSmallNumberAsNegative( c - '0', this.options); nextChar[0] = this.SkipWhitespaceJSON(); return(obj); } } // 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 = CBORDataUtilitiesTextString.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); }