podman
254 строки · 5.2 Кб
1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package json
6
7import (
8"bytes"
9"strconv"
10)
11
12// parseNumber reads the given []byte for a valid JSON number. If it is valid,
13// it returns the number of bytes. Parsing logic follows the definition in
14// https://tools.ietf.org/html/rfc7159#section-6, and is based off
15// encoding/json.isValidNumber function.
16func parseNumber(input []byte) (int, bool) {
17var n int
18
19s := input
20if len(s) == 0 {
21return 0, false
22}
23
24// Optional -
25if s[0] == '-' {
26s = s[1:]
27n++
28if len(s) == 0 {
29return 0, false
30}
31}
32
33// Digits
34switch {
35case s[0] == '0':
36s = s[1:]
37n++
38
39case '1' <= s[0] && s[0] <= '9':
40s = s[1:]
41n++
42for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
43s = s[1:]
44n++
45}
46
47default:
48return 0, false
49}
50
51// . followed by 1 or more digits.
52if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
53s = s[2:]
54n += 2
55for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
56s = s[1:]
57n++
58}
59}
60
61// e or E followed by an optional - or + and
62// 1 or more digits.
63if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
64s = s[1:]
65n++
66if s[0] == '+' || s[0] == '-' {
67s = s[1:]
68n++
69if len(s) == 0 {
70return 0, false
71}
72}
73for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
74s = s[1:]
75n++
76}
77}
78
79// Check that next byte is a delimiter or it is at the end.
80if n < len(input) && isNotDelim(input[n]) {
81return 0, false
82}
83
84return n, true
85}
86
87// numberParts is the result of parsing out a valid JSON number. It contains
88// the parts of a number. The parts are used for integer conversion.
89type numberParts struct {
90neg bool
91intp []byte
92frac []byte
93exp []byte
94}
95
96// parseNumber constructs numberParts from given []byte. The logic here is
97// similar to consumeNumber above with the difference of having to construct
98// numberParts. The slice fields in numberParts are subslices of the input.
99func parseNumberParts(input []byte) (numberParts, bool) {
100var neg bool
101var intp []byte
102var frac []byte
103var exp []byte
104
105s := input
106if len(s) == 0 {
107return numberParts{}, false
108}
109
110// Optional -
111if s[0] == '-' {
112neg = true
113s = s[1:]
114if len(s) == 0 {
115return numberParts{}, false
116}
117}
118
119// Digits
120switch {
121case s[0] == '0':
122// Skip first 0 and no need to store.
123s = s[1:]
124
125case '1' <= s[0] && s[0] <= '9':
126intp = s
127n := 1
128s = s[1:]
129for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
130s = s[1:]
131n++
132}
133intp = intp[:n]
134
135default:
136return numberParts{}, false
137}
138
139// . followed by 1 or more digits.
140if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
141frac = s[1:]
142n := 1
143s = s[2:]
144for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
145s = s[1:]
146n++
147}
148frac = frac[:n]
149}
150
151// e or E followed by an optional - or + and
152// 1 or more digits.
153if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
154s = s[1:]
155exp = s
156n := 0
157if s[0] == '+' || s[0] == '-' {
158s = s[1:]
159n++
160if len(s) == 0 {
161return numberParts{}, false
162}
163}
164for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
165s = s[1:]
166n++
167}
168exp = exp[:n]
169}
170
171return numberParts{
172neg: neg,
173intp: intp,
174frac: bytes.TrimRight(frac, "0"), // Remove unnecessary 0s to the right.
175exp: exp,
176}, true
177}
178
179// normalizeToIntString returns an integer string in normal form without the
180// E-notation for given numberParts. It will return false if it is not an
181// integer or if the exponent exceeds than max/min int value.
182func normalizeToIntString(n numberParts) (string, bool) {
183intpSize := len(n.intp)
184fracSize := len(n.frac)
185
186if intpSize == 0 && fracSize == 0 {
187return "0", true
188}
189
190var exp int
191if len(n.exp) > 0 {
192i, err := strconv.ParseInt(string(n.exp), 10, 32)
193if err != nil {
194return "", false
195}
196exp = int(i)
197}
198
199var num []byte
200if exp >= 0 {
201// For positive E, shift fraction digits into integer part and also pad
202// with zeroes as needed.
203
204// If there are more digits in fraction than the E value, then the
205// number is not an integer.
206if fracSize > exp {
207return "", false
208}
209
210// Make sure resulting digits are within max value limit to avoid
211// unnecessarily constructing a large byte slice that may simply fail
212// later on.
213const maxDigits = 20 // Max uint64 value has 20 decimal digits.
214if intpSize+exp > maxDigits {
215return "", false
216}
217
218// Set cap to make a copy of integer part when appended.
219num = n.intp[:len(n.intp):len(n.intp)]
220num = append(num, n.frac...)
221for i := 0; i < exp-fracSize; i++ {
222num = append(num, '0')
223}
224} else {
225// For negative E, shift digits in integer part out.
226
227// If there are fractions, then the number is not an integer.
228if fracSize > 0 {
229return "", false
230}
231
232// index is where the decimal point will be after adjusting for negative
233// exponent.
234index := intpSize + exp
235if index < 0 {
236return "", false
237}
238
239num = n.intp
240// If any of the digits being shifted to the right of the decimal point
241// is non-zero, then the number is not an integer.
242for i := index; i < intpSize; i++ {
243if num[i] != '0' {
244return "", false
245}
246}
247num = num[:index]
248}
249
250if n.neg {
251return "-" + string(num), true
252}
253return string(num), true
254}
255