|  | // Copyright 2018 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package json | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "strconv" | 
|  | ) | 
|  |  | 
|  | // parseNumber reads the given []byte for a valid JSON number. If it is valid, | 
|  | // it returns the number of bytes.  Parsing logic follows the definition in | 
|  | // https://tools.ietf.org/html/rfc7159#section-6, and is based off | 
|  | // encoding/json.isValidNumber function. | 
|  | func parseNumber(input []byte) (int, bool) { | 
|  | var n int | 
|  |  | 
|  | s := input | 
|  | if len(s) == 0 { | 
|  | return 0, false | 
|  | } | 
|  |  | 
|  | // Optional - | 
|  | if s[0] == '-' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | if len(s) == 0 { | 
|  | return 0, false | 
|  | } | 
|  | } | 
|  |  | 
|  | // Digits | 
|  | switch { | 
|  | case s[0] == '0': | 
|  | s = s[1:] | 
|  | n++ | 
|  |  | 
|  | case '1' <= s[0] && s[0] <= '9': | 
|  | s = s[1:] | 
|  | n++ | 
|  | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | } | 
|  |  | 
|  | default: | 
|  | return 0, false | 
|  | } | 
|  |  | 
|  | // . followed by 1 or more digits. | 
|  | if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { | 
|  | s = s[2:] | 
|  | n += 2 | 
|  | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | } | 
|  | } | 
|  |  | 
|  | // e or E followed by an optional - or + and | 
|  | // 1 or more digits. | 
|  | if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { | 
|  | s = s[1:] | 
|  | n++ | 
|  | if s[0] == '+' || s[0] == '-' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | if len(s) == 0 { | 
|  | return 0, false | 
|  | } | 
|  | } | 
|  | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | } | 
|  | } | 
|  |  | 
|  | // Check that next byte is a delimiter or it is at the end. | 
|  | if n < len(input) && isNotDelim(input[n]) { | 
|  | return 0, false | 
|  | } | 
|  |  | 
|  | return n, true | 
|  | } | 
|  |  | 
|  | // numberParts is the result of parsing out a valid JSON number. It contains | 
|  | // the parts of a number. The parts are used for integer conversion. | 
|  | type numberParts struct { | 
|  | neg  bool | 
|  | intp []byte | 
|  | frac []byte | 
|  | exp  []byte | 
|  | } | 
|  |  | 
|  | // parseNumber constructs numberParts from given []byte. The logic here is | 
|  | // similar to consumeNumber above with the difference of having to construct | 
|  | // numberParts. The slice fields in numberParts are subslices of the input. | 
|  | func parseNumberParts(input []byte) (numberParts, bool) { | 
|  | var neg bool | 
|  | var intp []byte | 
|  | var frac []byte | 
|  | var exp []byte | 
|  |  | 
|  | s := input | 
|  | if len(s) == 0 { | 
|  | return numberParts{}, false | 
|  | } | 
|  |  | 
|  | // Optional - | 
|  | if s[0] == '-' { | 
|  | neg = true | 
|  | s = s[1:] | 
|  | if len(s) == 0 { | 
|  | return numberParts{}, false | 
|  | } | 
|  | } | 
|  |  | 
|  | // Digits | 
|  | switch { | 
|  | case s[0] == '0': | 
|  | // Skip first 0 and no need to store. | 
|  | s = s[1:] | 
|  |  | 
|  | case '1' <= s[0] && s[0] <= '9': | 
|  | intp = s | 
|  | n := 1 | 
|  | s = s[1:] | 
|  | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | } | 
|  | intp = intp[:n] | 
|  |  | 
|  | default: | 
|  | return numberParts{}, false | 
|  | } | 
|  |  | 
|  | // . followed by 1 or more digits. | 
|  | if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { | 
|  | frac = s[1:] | 
|  | n := 1 | 
|  | s = s[2:] | 
|  | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | } | 
|  | frac = frac[:n] | 
|  | } | 
|  |  | 
|  | // e or E followed by an optional - or + and | 
|  | // 1 or more digits. | 
|  | if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { | 
|  | s = s[1:] | 
|  | exp = s | 
|  | n := 0 | 
|  | if s[0] == '+' || s[0] == '-' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | if len(s) == 0 { | 
|  | return numberParts{}, false | 
|  | } | 
|  | } | 
|  | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | 
|  | s = s[1:] | 
|  | n++ | 
|  | } | 
|  | exp = exp[:n] | 
|  | } | 
|  |  | 
|  | return numberParts{ | 
|  | neg:  neg, | 
|  | intp: intp, | 
|  | frac: bytes.TrimRight(frac, "0"), // Remove unnecessary 0s to the right. | 
|  | exp:  exp, | 
|  | }, true | 
|  | } | 
|  |  | 
|  | // normalizeToIntString returns an integer string in normal form without the | 
|  | // E-notation for given numberParts. It will return false if it is not an | 
|  | // integer or if the exponent exceeds than max/min int value. | 
|  | func normalizeToIntString(n numberParts) (string, bool) { | 
|  | intpSize := len(n.intp) | 
|  | fracSize := len(n.frac) | 
|  |  | 
|  | if intpSize == 0 && fracSize == 0 { | 
|  | return "0", true | 
|  | } | 
|  |  | 
|  | var exp int | 
|  | if len(n.exp) > 0 { | 
|  | i, err := strconv.ParseInt(string(n.exp), 10, 32) | 
|  | if err != nil { | 
|  | return "", false | 
|  | } | 
|  | exp = int(i) | 
|  | } | 
|  |  | 
|  | var num []byte | 
|  | if exp >= 0 { | 
|  | // For positive E, shift fraction digits into integer part and also pad | 
|  | // with zeroes as needed. | 
|  |  | 
|  | // If there are more digits in fraction than the E value, then the | 
|  | // number is not an integer. | 
|  | if fracSize > exp { | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | // Make sure resulting digits are within max value limit to avoid | 
|  | // unnecessarily constructing a large byte slice that may simply fail | 
|  | // later on. | 
|  | const maxDigits = 20 // Max uint64 value has 20 decimal digits. | 
|  | if intpSize+exp > maxDigits { | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | // Set cap to make a copy of integer part when appended. | 
|  | num = n.intp[:len(n.intp):len(n.intp)] | 
|  | num = append(num, n.frac...) | 
|  | for i := 0; i < exp-fracSize; i++ { | 
|  | num = append(num, '0') | 
|  | } | 
|  | } else { | 
|  | // For negative E, shift digits in integer part out. | 
|  |  | 
|  | // If there are fractions, then the number is not an integer. | 
|  | if fracSize > 0 { | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | // index is where the decimal point will be after adjusting for negative | 
|  | // exponent. | 
|  | index := intpSize + exp | 
|  | if index < 0 { | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | num = n.intp | 
|  | // If any of the digits being shifted to the right of the decimal point | 
|  | // is non-zero, then the number is not an integer. | 
|  | for i := index; i < intpSize; i++ { | 
|  | if num[i] != '0' { | 
|  | return "", false | 
|  | } | 
|  | } | 
|  | num = num[:index] | 
|  | } | 
|  |  | 
|  | if n.neg { | 
|  | return "-" + string(num), true | 
|  | } | 
|  | return string(num), true | 
|  | } |