Coverage Report

Created: 2026-11-12 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/swift-protobuf/Sources/SwiftProtobuf/JSONScanner.swift
Line
Count
Source
1
// Sources/SwiftProtobuf/JSONScanner.swift - JSON format decoding
2
//
3
// Copyright (c) 2014 - 2019 Apple Inc. and the project authors
4
// Licensed under Apache License v2.0 with Runtime Library Exception
5
//
6
// See LICENSE.txt for license information:
7
// https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
8
//
9
// -----------------------------------------------------------------------------
10
///
11
/// JSON format decoding engine.
12
///
13
// -----------------------------------------------------------------------------
14
15
#if canImport(FoundationEssentials)
16
import FoundationEssentials
17
#else
18
import Foundation
19
#endif
20
21
private let asciiBell = UInt8(7)
22
private let asciiBackspace = UInt8(8)
23
private let asciiTab = UInt8(9)
24
private let asciiNewLine = UInt8(10)
25
private let asciiVerticalTab = UInt8(11)
26
private let asciiFormFeed = UInt8(12)
27
private let asciiCarriageReturn = UInt8(13)
28
private let asciiZero = UInt8(ascii: "0")
29
private let asciiOne = UInt8(ascii: "1")
30
private let asciiSeven = UInt8(ascii: "7")
31
private let asciiNine = UInt8(ascii: "9")
32
private let asciiColon = UInt8(ascii: ":")
33
private let asciiPeriod = UInt8(ascii: ".")
34
private let asciiPlus = UInt8(ascii: "+")
35
private let asciiComma = UInt8(ascii: ",")
36
private let asciiSemicolon = UInt8(ascii: ";")
37
private let asciiDoubleQuote = UInt8(ascii: "\"")
38
private let asciiSingleQuote = UInt8(ascii: "\'")
39
private let asciiBackslash = UInt8(ascii: "\\")
40
private let asciiForwardSlash = UInt8(ascii: "/")
41
private let asciiHash = UInt8(ascii: "#")
42
private let asciiEqualSign = UInt8(ascii: "=")
43
private let asciiUnderscore = UInt8(ascii: "_")
44
private let asciiQuestionMark = UInt8(ascii: "?")
45
private let asciiSpace = UInt8(ascii: " ")
46
private let asciiOpenSquareBracket = UInt8(ascii: "[")
47
private let asciiCloseSquareBracket = UInt8(ascii: "]")
48
private let asciiOpenCurlyBracket = UInt8(ascii: "{")
49
private let asciiCloseCurlyBracket = UInt8(ascii: "}")
50
private let asciiOpenAngleBracket = UInt8(ascii: "<")
51
private let asciiCloseAngleBracket = UInt8(ascii: ">")
52
private let asciiMinus = UInt8(ascii: "-")
53
private let asciiLowerA = UInt8(ascii: "a")
54
private let asciiUpperA = UInt8(ascii: "A")
55
private let asciiLowerB = UInt8(ascii: "b")
56
private let asciiLowerE = UInt8(ascii: "e")
57
private let asciiUpperE = UInt8(ascii: "E")
58
private let asciiLowerF = UInt8(ascii: "f")
59
private let asciiUpperI = UInt8(ascii: "I")
60
private let asciiLowerL = UInt8(ascii: "l")
61
private let asciiLowerN = UInt8(ascii: "n")
62
private let asciiUpperN = UInt8(ascii: "N")
63
private let asciiLowerR = UInt8(ascii: "r")
64
private let asciiLowerS = UInt8(ascii: "s")
65
private let asciiLowerT = UInt8(ascii: "t")
66
private let asciiLowerU = UInt8(ascii: "u")
67
private let asciiLowerZ = UInt8(ascii: "z")
68
private let asciiUpperZ = UInt8(ascii: "Z")
69
70
17.3k
private func fromHexDigit(_ c: UnicodeScalar) -> UInt32? {
71
17.3k
    let n = c.value
72
17.3k
    if n >= 48 && n <= 57 {
73
3.72k
        return UInt32(n - 48)
74
13.5k
    }
75
13.5k
    switch n {
76
13.5k
    case 65, 97: return 10
77
13.5k
    case 66, 98: return 11
78
13.5k
    case 67, 99: return 12
79
13.5k
    case 68, 100: return 13
80
13.5k
    case 69, 101: return 14
81
13.5k
    case 70, 102: return 15
82
13.5k
    default:
83
79
        return nil
84
13.5k
    }
85
13.5k
}
86
87
// Decode both the RFC 4648 section 4 Base 64 encoding and the RFC
88
// 4648 section 5 Base 64 variant.  The section 5 variant is also
89
// known as "base64url" or the "URL-safe alphabet".
90
// Note that both "-" and "+" decode to 62 and "/" and "_" both
91
// decode as 63.
92
// swift-format-ignore: NoBlockComments
93
let base64Values: [Int] = [
94
    /* 0x00 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
95
    /* 0x10 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
96
    /* 0x20 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
97
    /* 0x30 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
98
    /* 0x40 */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
99
    /* 0x50 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
100
    /* 0x60 */ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
101
    /* 0x70 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
102
    /* 0x80 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
103
    /* 0x90 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
104
    /* 0xa0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
105
    /* 0xb0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
106
    /* 0xc0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
107
    /* 0xd0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
108
    /* 0xe0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
109
    /* 0xf0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
110
]
111
112
/// Returns a `Data` value containing bytes equivalent to the given
113
/// Base64-encoded string, or nil if the conversion fails.
114
///
115
/// Notes on Google's implementation (Base64Unescape() in strutil.cc):
116
///  * Google's C++ implementation accepts arbitrary whitespace
117
///    mixed in with the base-64 characters
118
///  * Google's C++ implementation ignores missing '=' characters
119
///    but if present, there must be the exact correct number of them.
120
///  * The conformance test requires us to accept both standard RFC4648
121
///    Base 64 encoding and the "URL and Filename Safe Alphabet" variant.
122
///
123
private func parseBytes(
124
    source: UnsafeRawBufferPointer,
125
    index: inout UnsafeRawBufferPointer.Index,
126
    end: UnsafeRawBufferPointer.Index
127
8.25k
) throws -> Data {
128
8.25k
    let c = source[index]
129
8.25k
    if c != asciiDoubleQuote {
130
25
        throw JSONDecodingError.malformedString
131
8.23k
    }
132
8.23k
    source.formIndex(after: &index)
133
8.23k
134
8.23k
    // Count the base-64 digits
135
8.23k
    // Ignore most unrecognized characters in this first pass,
136
8.23k
    // stop at the closing double quote.
137
8.23k
    let digitsStart = index
138
8.23k
    var rawChars = 0
139
8.23k
    var sawSection4Characters = false
140
8.23k
    var sawSection5Characters = false
141
3.13M
    while index != end {
142
3.13M
        var digit = source[index]
143
3.13M
        if digit == asciiDoubleQuote {
144
8.14k
            break
145
3.13M
        }
146
3.13M
147
3.13M
        if digit == asciiBackslash {
148
313
            source.formIndex(after: &index)
149
313
            if index == end {
150
1
                throw JSONDecodingError.malformedString
151
312
            }
152
312
            let escaped = source[index]
153
312
            switch escaped {
154
312
            case asciiLowerU:
155
1
                // TODO: Parse hex escapes such as \u0041.  Note that
156
1
                // such escapes are going to be extremely rare, so
157
1
                // there's little point in optimizing for them.
158
1
                throw JSONDecodingError.malformedString
159
312
            case asciiForwardSlash:
160
296
                digit = escaped
161
312
            default:
162
15
                // Reject \b \f \n \r \t \" or \\ and all illegal escapes
163
15
                throw JSONDecodingError.malformedString
164
312
            }
165
3.13M
        }
166
3.13M
167
3.13M
        if digit == asciiPlus || digit == asciiForwardSlash {
168
2.55k
            sawSection4Characters = true
169
3.12M
        } else if digit == asciiMinus || digit == asciiUnderscore {
170
7.68k
            sawSection5Characters = true
171
7.68k
        }
172
3.13M
        let k = base64Values[Int(digit)]
173
3.13M
        if k >= 0 {
174
3.02M
            rawChars += 1
175
3.02M
        }
176
3.13M
        source.formIndex(after: &index)
177
3.13M
    }
178
8.21k
179
8.21k
    // We reached the end without seeing the close quote
180
8.21k
    if index == end {
181
76
        throw JSONDecodingError.malformedString
182
8.14k
    }
183
8.14k
    // Reject mixed encodings.
184
8.14k
    if sawSection4Characters && sawSection5Characters {
185
2
        throw JSONDecodingError.malformedString
186
8.13k
    }
187
8.13k
188
8.13k
    // Allocate a Data object of exactly the right size
189
8.13k
    var value = Data(count: rawChars * 3 / 4)
190
8.13k
191
8.13k
    // Scan the digits again and populate the Data object.
192
8.13k
    // In this pass, we check for (and fail) if there are
193
8.13k
    // unexpected characters.  But we don't check for end-of-input,
194
8.13k
    // because the loop above already verified that there was
195
8.13k
    // a closing double quote.
196
8.13k
    index = digitsStart
197
8.13k
    try value.withUnsafeMutableBytes {
198
8.13k
        (body: UnsafeMutableRawBufferPointer) in
199
8.13k
        if var p = body.baseAddress, body.count > 0 {
200
4.48k
            var n = 0
201
4.48k
            var chars = 0  // # chars in current group
202
4.48k
            var padding = 0  // # padding '=' chars
203
2.78M
            digits: while true {
204
2.78M
                let digit = source[index]
205
2.78M
                var k = base64Values[Int(digit)]
206
2.78M
                if k < 0 {
207
4.80k
                    switch digit {
208
4.80k
                    case asciiDoubleQuote:
209
4.00k
                        break digits
210
4.80k
                    case asciiBackslash:
211
104
                        source.formIndex(after: &index)
212
104
                        let escaped = source[index]
213
104
                        switch escaped {
214
104
                        case asciiForwardSlash:
215
104
                            k = base64Values[Int(escaped)]
216
104
                        default:
217
0
                            // Note: Invalid backslash escapes were caught
218
0
                            // above; we should never get here.
219
0
                            throw JSONDecodingError.malformedString
220
104
                        }
221
4.80k
                    case asciiSpace:
222
221
                        source.formIndex(after: &index)
223
221
                        continue digits
224
4.80k
                    case asciiEqualSign:  // Count padding
225
1.44k
                        while true {
226
1.44k
                            switch source[index] {
227
1.44k
                            case asciiDoubleQuote:
228
411
                                break digits
229
1.44k
                            case asciiSpace:
230
202
                                break
231
1.44k
                            case 61:
232
805
                                padding += 1
233
1.44k
                            default:  // Only '=' and whitespace permitted
234
27
                                throw JSONDecodingError.malformedString
235
1.44k
                            }
236
1.00k
                            source.formIndex(after: &index)
237
1.00k
                        }
238
4.80k
                    default:
239
39
                        throw JSONDecodingError.malformedString
240
4.80k
                    }
241
2.77M
                }
242
2.77M
                n <<= 6
243
2.77M
                n |= k
244
2.77M
                chars += 1
245
2.77M
                if chars == 4 {
246
693k
                    p[0] = UInt8(truncatingIfNeeded: n >> 16)
247
693k
                    p[1] = UInt8(truncatingIfNeeded: n >> 8)
248
693k
                    p[2] = UInt8(truncatingIfNeeded: n)
249
693k
                    p += 3
250
693k
                    chars = 0
251
693k
                    n = 0
252
693k
                }
253
2.77M
                source.formIndex(after: &index)
254
2.77M
            }
255
4.41k
            switch chars {
256
4.41k
            case 3:
257
1.35k
                p[0] = UInt8(truncatingIfNeeded: n >> 10)
258
1.35k
                p[1] = UInt8(truncatingIfNeeded: n >> 2)
259
1.35k
                if padding == 1 || padding == 0 {
260
1.35k
                    return
261
1.35k
                }
262
4.41k
            case 2:
263
1.18k
                p[0] = UInt8(truncatingIfNeeded: n >> 4)
264
1.18k
                if padding == 2 || padding == 0 {
265
1.17k
                    return
266
1.17k
                }
267
4.41k
            case 0:
268
1.87k
                if padding == 0 {
269
1.86k
                    return
270
1.86k
                }
271
4.41k
            default:
272
5
                break
273
4.41k
            }
274
23
            throw JSONDecodingError.malformedString
275
4.48k
        }
276
8.04k
    }
277
8.04k
    source.formIndex(after: &index)
278
8.04k
    return value
279
8.25k
}
280
281
// JSON encoding allows a variety of \-escapes, including
282
// escaping UTF-16 code points (which may be surrogate pairs).
283
60.5k
private func decodeString(_ s: String) -> String? {
284
60.5k
    var out = String.UnicodeScalarView()
285
60.5k
    var chars = s.unicodeScalars.makeIterator()
286
8.78M
    while let c = chars.next() {
287
8.78M
        switch c.value {
288
8.78M
        case UInt32(asciiBackslash):  // backslash
289
78.9k
            if let escaped = chars.next() {
290
78.9k
                switch escaped.value {
291
78.9k
                case UInt32(asciiLowerU):  // "\u"
292
4.25k
                    // Exactly 4 hex digits:
293
4.25k
                    if let digit1 = chars.next(),
294
4.25k
                        let d1 = fromHexDigit(digit1),
295
4.25k
                        let digit2 = chars.next(),
296
4.25k
                        let d2 = fromHexDigit(digit2),
297
4.25k
                        let digit3 = chars.next(),
298
4.25k
                        let d3 = fromHexDigit(digit3),
299
4.25k
                        let digit4 = chars.next(),
300
4.25k
                        let d4 = fromHexDigit(digit4)
301
4.25k
                    {
302
4.13k
                        let codePoint = ((d1 * 16 + d2) * 16 + d3) * 16 + d4
303
4.13k
                        if let scalar = UnicodeScalar(codePoint) {
304
3.89k
                            out.append(scalar)
305
3.89k
                        } else if codePoint < 0xD800 || codePoint >= 0xE000 {
306
0
                            // Not a valid Unicode scalar.
307
0
                            return nil
308
241
                        } else if codePoint >= 0xDC00 {
309
20
                            // Low surrogate without a preceding high surrogate.
310
20
                            return nil
311
221
                        } else {
312
221
                            // We have a high surrogate (in the range 0xD800..<0xDC00), so
313
221
                            // verify that it is followed by a low surrogate.
314
221
                            guard chars.next() == "\\", chars.next() == "u" else {
315
72
                                // High surrogate was not followed by a Unicode escape sequence.
316
72
                                return nil
317
149
                            }
318
149
                            if let digit1 = chars.next(),
319
149
                                let d1 = fromHexDigit(digit1),
320
149
                                let digit2 = chars.next(),
321
149
                                let d2 = fromHexDigit(digit2),
322
149
                                let digit3 = chars.next(),
323
149
                                let d3 = fromHexDigit(digit3),
324
149
                                let digit4 = chars.next(),
325
149
                                let d4 = fromHexDigit(digit4)
326
149
                            {
327
138
                                let follower = ((d1 * 16 + d2) * 16 + d3) * 16 + d4
328
138
                                guard 0xDC00 <= follower && follower < 0xE000 else {
329
21
                                    // High surrogate was not followed by a low surrogate.
330
21
                                    return nil
331
117
                                }
332
117
                                let high = codePoint - 0xD800
333
117
                                let low = follower - 0xDC00
334
117
                                let composed = 0x10000 | high << 10 | low
335
117
                                guard let composedScalar = UnicodeScalar(composed) else {
336
0
                                    // Composed value is not a valid Unicode scalar.
337
0
                                    return nil
338
117
                                }
339
117
                                out.append(composedScalar)
340
117
                            } else {
341
11
                                // Malformed \u escape for low surrogate
342
11
                                return nil
343
117
                            }
344
4.00k
                        }
345
4.00k
                    } else {
346
123
                        // Malformed \u escape
347
123
                        return nil
348
123
                    }
349
78.9k
                case UInt32(asciiLowerB):  // \b
350
32.5k
                    out.append("\u{08}")
351
78.9k
                case UInt32(asciiLowerF):  // \f
352
26.0k
                    out.append("\u{0c}")
353
78.9k
                case UInt32(asciiLowerN):  // \n
354
7.29k
                    out.append("\u{0a}")
355
78.9k
                case UInt32(asciiLowerR):  // \r
356
1.69k
                    out.append("\u{0d}")
357
78.9k
                case UInt32(asciiLowerT):  // \t
358
2.36k
                    out.append("\u{09}")
359
78.9k
                case UInt32(asciiDoubleQuote), UInt32(asciiBackslash),
360
4.68k
                    UInt32(asciiForwardSlash):  // " \ /
361
4.68k
                    out.append(escaped)
362
78.9k
                default:
363
90
                    return nil  // Unrecognized escape
364
78.9k
                }
365
78.6k
            } else {
366
0
                return nil  // Input ends with backslash
367
0
            }
368
8.78M
        default:
369
8.70M
            out.append(c)
370
8.78M
        }
371
8.78M
    }
372
60.1k
    return String(out)
373
60.5k
}
374
375
///
376
/// The basic scanner support is entirely private
377
///
378
/// For performance, it works directly against UTF-8 bytes in memory.
379
internal struct JSONScanner {
380
    private let source: UnsafeRawBufferPointer
381
    private var index: UnsafeRawBufferPointer.Index
382
11.9k
    private var numberParser = DoubleParser()
383
    internal let options: JSONDecodingOptions
384
    internal let extensions: any ExtensionMap
385
    internal var recursionBudget: Int
386
387
    /// True if the scanner has read all of the data from the source, with the
388
    /// exception of any trailing whitespace (which is consumed by reading this
389
    /// property).
390
    internal var complete: Bool {
391
18
        mutating get {
392
18
            skipWhitespace()
393
18
            return !hasMoreContent
394
18
        }
395
    }
396
397
    /// True if the scanner has not yet reached the end of the source.
398
48.2M
    private var hasMoreContent: Bool {
399
48.2M
        index != source.endIndex
400
48.2M
    }
401
402
    /// The byte (UTF-8 code unit) at the scanner's current position.
403
86.3M
    private var currentByte: UInt8 {
404
86.3M
        source[index]
405
86.3M
    }
406
407
    internal init(
408
        source: UnsafeRawBufferPointer,
409
        options: JSONDecodingOptions,
410
        extensions: (any ExtensionMap)?
411
1.13k
    ) {
412
1.13k
        self.source = source
413
1.13k
        self.index = source.startIndex
414
1.13k
        self.recursionBudget = options.messageDepthLimit
415
1.13k
        self.options = options
416
1.13k
        self.extensions = extensions ?? SimpleExtensionMap()
417
1.13k
    }
418
419
8.71k
    internal mutating func incrementRecursionDepth() throws {
420
8.71k
        recursionBudget -= 1
421
8.71k
        if recursionBudget < 0 {
422
0
            throw JSONDecodingError.messageDepthLimit
423
8.71k
        }
424
8.71k
    }
425
426
4.21k
    internal mutating func decrementRecursionDepth() {
427
4.21k
        recursionBudget += 1
428
4.21k
        // This should never happen, if it does, something is probably corrupting memory, and
429
4.21k
        // simply throwing doesn't make much sense.
430
4.21k
        if recursionBudget > options.messageDepthLimit {
431
0
            fatalError("Somehow JSONDecoding unwound more objects than it started")
432
0
        }
433
4.21k
    }
434
435
    /// Advances the scanner to the next position in the source.
436
36.7M
    private mutating func advance() {
437
36.7M
        source.formIndex(after: &index)
438
36.7M
    }
439
440
    /// Skip whitespace.
441
7.31M
    private mutating func skipWhitespace() {
442
7.86M
        while hasMoreContent {
443
7.86M
            let u = currentByte
444
7.86M
            switch u {
445
7.86M
            case asciiSpace, asciiTab, asciiNewLine, asciiCarriageReturn:
446
546k
                advance()
447
7.86M
            default:
448
7.31M
                return
449
7.86M
            }
450
546k
        }
451
6.25k
    }
452
453
    /// Returns (but does not consume) the next non-whitespace
454
    /// character.  This is used by google.protobuf.Value, for
455
    /// example, for custom JSON parsing.
456
44
    internal mutating func peekOneCharacter() throws -> Character {
457
44
        skipWhitespace()
458
44
        guard hasMoreContent else {
459
0
            throw JSONDecodingError.truncated
460
44
        }
461
44
        return Character(UnicodeScalar(UInt32(currentByte))!)
462
44
    }
463
464
    // Parse the leading UInt64 from the provided utf8 bytes.
465
    //
466
    // This is called in three different situations:
467
    //
468
    // * Unquoted number.
469
    //
470
    // * Simple quoted number.  If a number is quoted but has no
471
    //   backslashes, the caller can use this directly on the UTF8 by
472
    //   just verifying the quote marks.  This code returns `nil` if it
473
    //   sees a backslash, in which case the caller will need to handle ...
474
    //
475
    // * Complex quoted number.  In this case, the caller must parse the
476
    //   quoted value as a string, then convert the string to utf8 and
477
    //   use this to parse the result.  This is slow but fortunately
478
    //   rare.
479
    //
480
    // In the common case where the number is written in integer form,
481
    // this code does a simple straight conversion.  If the number is in
482
    // floating-point format, this uses a slower and less accurate
483
    // approach: it identifies a substring comprising a float, and then
484
    // uses Double() and UInt64() to convert that string to an unsigned
485
    // integer.  In particular, it cannot preserve full 64-bit integer
486
    // values when they are written in floating-point format.
487
    //
488
    // If it encounters a "\" backslash character, it returns a nil.  This
489
    // is used by callers that are parsing quoted numbers.  See nextSInt()
490
    // and nextUInt() below.
491
    private func parseBareUInt64(
492
        source: UnsafeRawBufferPointer,
493
        index: inout UnsafeRawBufferPointer.Index,
494
        end: UnsafeRawBufferPointer.Index
495
94.5k
    ) throws -> UInt64? {
496
94.5k
        if index == end {
497
10
            throw JSONDecodingError.truncated
498
94.5k
        }
499
94.5k
        let start = index
500
94.5k
        let c = source[index]
501
94.5k
        switch c {
502
94.5k
        case asciiZero:  // 0
503
40.7k
            source.formIndex(after: &index)
504
40.7k
            if index != end {
505
40.7k
                let after = source[index]
506
40.7k
                switch after {
507
40.7k
                case asciiZero...asciiNine:  // 0...9
508
3
                    // leading '0' forbidden unless it is the only digit
509
3
                    throw JSONDecodingError.leadingZero
510
40.7k
                case asciiPeriod, asciiLowerE, asciiUpperE:  // . e
511
4.87k
                    // Slow path: JSON numbers can be written in floating-point notation
512
4.87k
                    index = start
513
4.87k
                    if let d = try parseBareDouble(
514
4.87k
                        source: source,
515
4.87k
                        index: &index,
516
4.87k
                        end: end
517
4.87k
                    ) {
518
4.86k
                        if let u = UInt64(exactly: d) {
519
4.85k
                            return u
520
4.85k
                        }
521
3
                    }
522
3
                    throw JSONDecodingError.malformedNumber
523
40.7k
                case asciiBackslash:
524
4
                    return nil
525
40.7k
                default:
526
35.8k
                    return 0
527
40.7k
                }
528
40.7k
            }
529
34
            return 0
530
94.5k
        case asciiOne...asciiNine:  // 1...9
531
53.6k
            var n = 0 as UInt64
532
135k
            while index != end {
533
135k
                let digit = source[index]
534
135k
                switch digit {
535
135k
                case asciiZero...asciiNine:  // 0...9
536
82.1k
                    let val = UInt64(digit - asciiZero)
537
82.1k
                    if n > UInt64.max / 10 || n * 10 > UInt64.max - val {
538
6
                        throw JSONDecodingError.numberRange
539
82.1k
                    }
540
82.1k
                    source.formIndex(after: &index)
541
82.1k
                    n = n * 10 + val
542
135k
                case asciiPeriod, asciiLowerE, asciiUpperE:  // . e
543
4.13k
                    // Slow path: JSON allows floating-point notation for integers
544
4.13k
                    index = start
545
4.13k
                    if let d = try parseBareDouble(
546
4.13k
                        source: source,
547
4.13k
                        index: &index,
548
4.13k
                        end: end
549
4.13k
                    ) {
550
4.09k
                        if let u = UInt64(exactly: d) {
551
4.08k
                            return u
552
4.08k
                        }
553
7
                    }
554
7
                    throw JSONDecodingError.malformedNumber
555
135k
                case asciiBackslash:
556
12
                    return nil
557
135k
                default:
558
48.7k
                    return n
559
135k
                }
560
82.1k
            }
561
678
            return n
562
94.5k
        case asciiBackslash:
563
21
            return nil
564
94.5k
        default:
565
120
            throw JSONDecodingError.malformedNumber
566
94.5k
        }
567
94.5k
    }
568
569
    // Parse the leading Int64 from the provided utf8.
570
    //
571
    // This uses parseBareUInt64() to do the heavy lifting;
572
    // we just check for a leading minus and negate the result
573
    // as necessary.
574
    //
575
    // As with parseBareUInt64(), if it encounters a "\" backslash
576
    // character, it returns a nil.  This allows callers to use this to
577
    // do a "fast-path" decode of simple quoted numbers by parsing the
578
    // UTF8 directly, only falling back to a full String decode when
579
    // absolutely necessary.
580
    private func parseBareSInt64(
581
        source: UnsafeRawBufferPointer,
582
        index: inout UnsafeRawBufferPointer.Index,
583
        end: UnsafeRawBufferPointer.Index
584
52.2k
    ) throws -> Int64? {
585
52.2k
        if index == end {
586
23
            throw JSONDecodingError.truncated
587
52.2k
        }
588
52.2k
        let c = source[index]
589
52.2k
        if c == asciiMinus {  // -
590
9.08k
            source.formIndex(after: &index)
591
9.08k
            if index == end {
592
7
                throw JSONDecodingError.truncated
593
9.08k
            }
594
9.08k
            // character after '-' must be digit
595
9.08k
            let digit = source[index]
596
9.08k
            if digit < asciiZero || digit > asciiNine {
597
8
                throw JSONDecodingError.malformedNumber
598
9.07k
            }
599
9.07k
            if let n = try parseBareUInt64(source: source, index: &index, end: end) {
600
9.06k
                let limit: UInt64 = 0x8000_0000_0000_0000  // -Int64.min
601
9.06k
                if n >= limit {
602
63
                    if n > limit {
603
62
                        // Too large negative number
604
62
                        throw JSONDecodingError.numberRange
605
62
                    } else {
606
1
                        return Int64.min  // Special case for Int64.min
607
1
                    }
608
8.99k
                }
609
8.99k
                return -Int64(bitPattern: n)
610
9.06k
            } else {
611
5
                return nil
612
5
            }
613
43.0k
        } else if let n = try parseBareUInt64(source: source, index: &index, end: end) {
614
42.9k
            if n > UInt64(bitPattern: Int64.max) {
615
44
                throw JSONDecodingError.numberRange
616
42.9k
            }
617
42.9k
            return Int64(bitPattern: n)
618
42.9k
        } else {
619
15
            return nil
620
15
        }
621
52.2k
    }
622
623
    // Identify a floating-point token in the upcoming UTF8 bytes.
624
    //
625
    // This implements the full grammar defined by the JSON RFC 7159.
626
    // Note that Swift's string-to-number conversions are much more
627
    // lenient, so this is necessary if we want to accurately reject
628
    // malformed JSON numbers.
629
    //
630
    // This is used by nextDouble() and nextFloat() to parse double and
631
    // floating-point values, including values that happen to be in quotes.
632
    // It's also used by the slow path in parseBareSInt64() and parseBareUInt64()
633
    // above to handle integer values that are written in float-point notation.
634
    private func parseBareDouble(
635
        source: UnsafeRawBufferPointer,
636
        index: inout UnsafeRawBufferPointer.Index,
637
        end: UnsafeRawBufferPointer.Index
638
252k
    ) throws -> Double? {
639
252k
        // RFC 7159 defines the grammar for JSON numbers as:
640
252k
        // number = [ minus ] int [ frac ] [ exp ]
641
252k
        if index == end {
642
2
            throw JSONDecodingError.truncated
643
252k
        }
644
252k
        let start = index
645
252k
        var c = source[index]
646
252k
        if c == asciiBackslash {
647
21
            return nil
648
252k
        }
649
252k
650
252k
        // Optional leading minus sign
651
252k
        if c == asciiMinus {  // -
652
4.73k
            source.formIndex(after: &index)
653
4.73k
            if index == end {
654
4
                index = start
655
4
                throw JSONDecodingError.truncated
656
4.73k
            }
657
4.73k
            c = source[index]
658
4.73k
            if c == asciiBackslash {
659
4
                return nil
660
4.73k
            }
661
248k
        } else if c == asciiUpperN {  // Maybe NaN?
662
6
            // Return nil, let the caller deal with it.
663
6
            return nil
664
252k
        }
665
252k
666
252k
        if c == asciiUpperI {  // Maybe Infinity, Inf, -Infinity, or -Inf ?
667
10
            // Return nil, let the caller deal with it.
668
10
            return nil
669
252k
        }
670
252k
671
252k
        // Integer part can be zero or a series of digits not starting with zero
672
252k
        // int = zero / (digit1-9 *DIGIT)
673
252k
        switch c {
674
252k
        case asciiZero:
675
132k
            // First digit can be zero only if not followed by a digit
676
132k
            source.formIndex(after: &index)
677
132k
            if index == end {
678
12
                return 0.0
679
132k
            }
680
132k
            c = source[index]
681
132k
            if c == asciiBackslash {
682
4
                return nil
683
132k
            }
684
132k
            if c >= asciiZero && c <= asciiNine {
685
11
                throw JSONDecodingError.leadingZero
686
11
            }
687
252k
        case asciiOne...asciiNine:
688
704k
            while c >= asciiZero && c <= asciiNine {
689
584k
                source.formIndex(after: &index)
690
584k
                if index == end {
691
58
                    if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
692
54
                        return d
693
54
                    } else {
694
4
                        throw JSONDecodingError.invalidUTF8
695
4
                    }
696
584k
                }
697
584k
                c = source[index]
698
584k
                if c == asciiBackslash {
699
25
                    return nil
700
584k
                }
701
584k
            }
702
252k
        default:
703
254
            // Integer part cannot be empty
704
254
            throw JSONDecodingError.malformedNumber
705
252k
        }
706
252k
707
252k
        // frac = decimal-point 1*DIGIT
708
252k
        if c == asciiPeriod {
709
1.73k
            source.formIndex(after: &index)
710
1.73k
            if index == end {
711
7
                // decimal point must have a following digit
712
7
                throw JSONDecodingError.truncated
713
1.72k
            }
714
1.72k
            c = source[index]
715
1.72k
            switch c {
716
1.72k
            case asciiZero...asciiNine:  // 0...9
717
2.02M
                while c >= asciiZero && c <= asciiNine {
718
2.02M
                    source.formIndex(after: &index)
719
2.02M
                    if index == end {
720
31
                        if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
721
24
                            return d
722
24
                        } else {
723
7
                            throw JSONDecodingError.invalidUTF8
724
7
                        }
725
2.02M
                    }
726
2.02M
                    c = source[index]
727
2.02M
                    if c == asciiBackslash {
728
13
                        return nil
729
2.02M
                    }
730
2.02M
                }
731
1.72k
            case asciiBackslash:
732
4
                return nil
733
1.72k
            default:
734
19
                // decimal point must be followed by at least one digit
735
19
                throw JSONDecodingError.malformedNumber
736
1.72k
            }
737
252k
        }
738
252k
739
252k
        // exp = e [ minus / plus ] 1*DIGIT
740
252k
        if c == asciiLowerE || c == asciiUpperE {
741
28.2k
            source.formIndex(after: &index)
742
28.2k
            if index == end {
743
14
                // "e" must be followed by +,-, or digit
744
14
                throw JSONDecodingError.truncated
745
28.2k
            }
746
28.2k
            c = source[index]
747
28.2k
            if c == asciiBackslash {
748
4
                return nil
749
28.2k
            }
750
28.2k
            if c == asciiPlus || c == asciiMinus {  // + -
751
1.45k
                source.formIndex(after: &index)
752
1.45k
                if index == end {
753
2
                    // must be at least one digit in exponent
754
2
                    throw JSONDecodingError.truncated
755
1.45k
                }
756
1.45k
                c = source[index]
757
1.45k
                if c == asciiBackslash {
758
4
                    return nil
759
1.44k
                }
760
28.2k
            }
761
28.2k
            switch c {
762
28.2k
            case asciiZero...asciiNine:
763
406k
                while c >= asciiZero && c <= asciiNine {
764
378k
                    source.formIndex(after: &index)
765
378k
                    if index == end {
766
70
                        if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
767
65
                            return d
768
65
                        } else {
769
5
                            throw JSONDecodingError.invalidUTF8
770
5
                        }
771
378k
                    }
772
378k
                    c = source[index]
773
378k
                    if c == asciiBackslash {
774
4
                        return nil
775
378k
                    }
776
378k
                }
777
28.2k
            default:
778
47
                // must be at least one digit in exponent
779
47
                throw JSONDecodingError.malformedNumber
780
28.2k
            }
781
252k
        }
782
252k
        if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
783
252k
            return d
784
252k
        } else {
785
38
            throw JSONDecodingError.invalidUTF8
786
38
        }
787
252k
    }
788
789
    /// Returns a fully-parsed string with all backslash escapes
790
    /// correctly processed, or nil if next token is not a string.
791
    ///
792
    /// Assumes the leading quote has been verified (but not consumed)
793
79.7k
    private mutating func parseOptionalQuotedString() -> String? {
794
79.7k
        // Caller has already asserted that currentByte == quote here
795
79.7k
        var sawBackslash = false
796
79.7k
        advance()
797
79.7k
        let start = index
798
10.2M
        while hasMoreContent {
799
10.2M
            switch currentByte {
800
10.2M
            case asciiDoubleQuote:  // "
801
79.4k
                let s = utf8ToString(bytes: source, start: start, end: index)
802
79.4k
                advance()
803
79.4k
                if let t = s {
804
79.4k
                    if sawBackslash {
805
60.5k
                        return decodeString(t)
806
60.5k
                    } else {
807
18.9k
                        return t
808
18.9k
                    }
809
79.4k
                } else {
810
15
                    return nil  // Invalid UTF8
811
15
                }
812
10.2M
            case asciiBackslash:  //  \
813
79.2k
                advance()
814
79.2k
                guard hasMoreContent else {
815
19
                    return nil  // Unterminated escape
816
79.2k
                }
817
79.2k
                sawBackslash = true
818
10.2M
            case 0..<asciiSpace:
819
249
                // Unescaped control characters (U+0000...U+001F) are not
820
249
                // allowed inside a JSON string; they must be escaped.
821
249
                return nil
822
10.2M
            default:
823
10.1M
                break
824
10.2M
            }
825
10.1M
            advance()
826
10.1M
        }
827
73
        return nil  // Unterminated quoted string
828
79.7k
    }
829
830
    /// Parse an unsigned integer, whether or not its quoted.
831
    /// This also handles cases such as quoted numbers that have
832
    /// backslash escapes in them.
833
    ///
834
    /// This supports the full range of UInt64 (whether quoted or not)
835
    /// unless the number is written in floating-point format.  In that
836
    /// case, we decode it with only Double precision.
837
0
    internal mutating func nextUInt() throws -> UInt64 {
838
0
        skipWhitespace()
839
0
        guard hasMoreContent else {
840
0
            throw JSONDecodingError.truncated
841
0
        }
842
0
        let c = currentByte
843
0
        if c == asciiDoubleQuote {
844
0
            let start = index
845
0
            advance()
846
0
            if let u = try parseBareUInt64(
847
0
                source: source,
848
0
                index: &index,
849
0
                end: source.endIndex
850
0
            ) {
851
0
                guard hasMoreContent else {
852
0
                    throw JSONDecodingError.truncated
853
0
                }
854
0
                if currentByte != asciiDoubleQuote {
855
0
                    throw JSONDecodingError.malformedNumber
856
0
                }
857
0
                advance()
858
0
                return u
859
0
            } else {
860
0
                // Couldn't parse because it had a "\" in the string,
861
0
                // so parse out the quoted string and then reparse
862
0
                // the result to get a UInt.
863
0
                index = start
864
0
                let s = try nextQuotedString()
865
0
                let raw = s.data(using: String.Encoding.utf8)!
866
12
                let n = try raw.withUnsafeBytes {
867
12
                    (body: UnsafeRawBufferPointer) -> UInt64? in
868
12
                    if body.count > 0 {
869
12
                        var index = body.startIndex
870
12
                        let end = body.endIndex
871
12
                        if let u = try parseBareUInt64(
872
12
                            source: body,
873
12
                            index: &index,
874
12
                            end: end
875
12
                        ) {
876
1
                            if index == end {
877
0
                                return u
878
1
                            }
879
4
                        }
880
4
                    }
881
4
                    return nil
882
12
                }
883
0
                if let n = n {
884
0
                    return n
885
0
                }
886
0
            }
887
0
        } else if let u = try parseBareUInt64(
888
0
            source: source,
889
0
            index: &index,
890
0
            end: source.endIndex
891
0
        ) {
892
0
            return u
893
0
        }
894
0
        throw JSONDecodingError.malformedNumber
895
0
    }
896
897
    /// Parse a signed integer, quoted or not, including handling
898
    /// backslash escapes for quoted values.
899
    ///
900
    /// This supports the full range of Int64 (whether quoted or not)
901
    /// unless the number is written in floating-point format.  In that
902
    /// case, we decode it with only Double precision.
903
2
    internal mutating func nextSInt() throws -> Int64 {
904
2
        skipWhitespace()
905
2
        guard hasMoreContent else {
906
0
            throw JSONDecodingError.truncated
907
2
        }
908
2
        let c = currentByte
909
2
        if c == asciiDoubleQuote {
910
1
            let start = index
911
1
            advance()
912
1
            if let s = try parseBareSInt64(
913
1
                source: source,
914
1
                index: &index,
915
1
                end: source.endIndex
916
1
            ) {
917
1
                guard hasMoreContent else {
918
0
                    throw JSONDecodingError.truncated
919
1
                }
920
1
                if currentByte != asciiDoubleQuote {
921
0
                    throw JSONDecodingError.malformedNumber
922
1
                }
923
1
                advance()
924
1
                return s
925
1
            } else {
926
0
                // Couldn't parse because it had a "\" in the string,
927
0
                // so parse out the quoted string and then reparse
928
0
                // the result as an SInt.
929
0
                index = start
930
0
                let s = try nextQuotedString()
931
0
                let raw = s.data(using: String.Encoding.utf8)!
932
9
                let n = try raw.withUnsafeBytes {
933
9
                    (body: UnsafeRawBufferPointer) -> Int64? in
934
9
                    if body.count > 0 {
935
9
                        var index = body.startIndex
936
9
                        let end = body.endIndex
937
9
                        if let s = try parseBareSInt64(
938
9
                            source: body,
939
9
                            index: &index,
940
9
                            end: end
941
9
                        ) {
942
2
                            if index == end {
943
0
                                return s
944
2
                            }
945
8
                        }
946
8
                    }
947
8
                    return nil
948
9
                }
949
0
                if let n = n {
950
0
                    return n
951
0
                }
952
0
            }
953
0
        } else if let s = try parseBareSInt64(
954
2
            source: source,
955
2
            index: &index,
956
2
            end: source.endIndex
957
2
        ) {
958
1
            return s
959
1
        }
960
0
        throw JSONDecodingError.malformedNumber
961
2
    }
962
963
    /// Parse the next Float value, regardless of whether it
964
    /// is quoted, including handling backslash escapes for
965
    /// quoted strings.
966
0
    internal mutating func nextFloat() throws -> Float {
967
0
        skipWhitespace()
968
0
        guard hasMoreContent else {
969
0
            throw JSONDecodingError.truncated
970
0
        }
971
0
        let c = currentByte
972
0
        if c == asciiDoubleQuote {  // "
973
0
            let start = index
974
0
            advance()
975
0
            if let d = try parseBareDouble(
976
0
                source: source,
977
0
                index: &index,
978
0
                end: source.endIndex
979
0
            ) {
980
0
                guard hasMoreContent else {
981
0
                    throw JSONDecodingError.truncated
982
0
                }
983
0
                if currentByte != asciiDoubleQuote {
984
0
                    throw JSONDecodingError.malformedNumber
985
0
                }
986
0
                advance()
987
0
                // A value that parses as a finite Double can still be out of
988
0
                // range for Float (for example "1e39"), in which case the
989
0
                // conversion yields an infinity. Reject it, matching the
990
0
                // unquoted path below.
991
0
                let f = Float(d)
992
0
                if f.isFinite {
993
0
                    return f
994
0
                }
995
0
                throw JSONDecodingError.malformedNumber
996
0
            } else {
997
0
                // Slow Path: parseBareDouble returned nil: It might be
998
0
                // a valid float, but had something that
999
0
                // parseBareDouble cannot directly handle.  So we reset,
1000
0
                // try a full string parse, then examine the result:
1001
0
                index = start
1002
0
                let s = try nextQuotedString()
1003
0
                switch s {
1004
0
                case "NaN": return Float.nan
1005
0
                case "Inf": return Float.infinity
1006
0
                case "-Inf": return -Float.infinity
1007
0
                case "Infinity": return Float.infinity
1008
0
                case "-Infinity": return -Float.infinity
1009
0
                default:
1010
0
                    let raw = s.data(using: String.Encoding.utf8)!
1011
38
                    let n = try raw.withUnsafeBytes {
1012
38
                        (body: UnsafeRawBufferPointer) -> Float? in
1013
38
                        if body.count > 0 {
1014
38
                            var index = body.startIndex
1015
38
                            let end = body.endIndex
1016
38
                            if let d = try parseBareDouble(
1017
38
                                source: body,
1018
38
                                index: &index,
1019
38
                                end: end
1020
38
                            ) {
1021
17
                                let f = Float(d)
1022
17
                                if index == end && f.isFinite {
1023
0
                                    return f
1024
17
                                }
1025
30
                            }
1026
30
                        }
1027
30
                        return nil
1028
38
                    }
1029
0
                    if let n = n {
1030
0
                        return n
1031
0
                    }
1032
0
                }
1033
0
            }
1034
0
        } else {
1035
0
            if let d = try parseBareDouble(
1036
0
                source: source,
1037
0
                index: &index,
1038
0
                end: source.endIndex
1039
0
            ) {
1040
0
                let f = Float(d)
1041
0
                if f.isFinite {
1042
0
                    return f
1043
0
                }
1044
0
            }
1045
0
        }
1046
0
        throw JSONDecodingError.malformedNumber
1047
0
    }
1048
1049
    /// Parse the next Double value, regardless of whether it
1050
    /// is quoted, including handling backslash escapes for
1051
    /// quoted strings.
1052
5
    internal mutating func nextDouble() throws -> Double {
1053
5
        skipWhitespace()
1054
5
        guard hasMoreContent else {
1055
0
            throw JSONDecodingError.truncated
1056
5
        }
1057
5
        let c = currentByte
1058
5
        if c == asciiDoubleQuote {  // "
1059
1
            let start = index
1060
1
            advance()
1061
1
            if let d = try parseBareDouble(
1062
1
                source: source,
1063
1
                index: &index,
1064
1
                end: source.endIndex
1065
1
            ) {
1066
0
                guard hasMoreContent else {
1067
0
                    throw JSONDecodingError.truncated
1068
0
                }
1069
0
                if currentByte != asciiDoubleQuote {
1070
0
                    throw JSONDecodingError.malformedNumber
1071
0
                }
1072
0
                advance()
1073
0
                return d
1074
1
            } else {
1075
1
                // Slow Path: parseBareDouble returned nil: It might be
1076
1
                // a valid float, but had something that
1077
1
                // parseBareDouble cannot directly handle.  So we reset,
1078
1
                // try a full string parse, then examine the result:
1079
1
                index = start
1080
1
                let s = try nextQuotedString()
1081
1
                switch s {
1082
1
                case "NaN": return Double.nan
1083
1
                case "Inf": return Double.infinity
1084
1
                case "-Inf": return -Double.infinity
1085
1
                case "Infinity": return Double.infinity
1086
1
                case "-Infinity": return -Double.infinity
1087
1
                default:
1088
1
                    let raw = s.data(using: String.Encoding.utf8)!
1089
18
                    let n = try raw.withUnsafeBytes {
1090
18
                        (body: UnsafeRawBufferPointer) -> Double? in
1091
18
                        if body.count > 0 {
1092
18
                            var index = body.startIndex
1093
18
                            let end = body.endIndex
1094
18
                            if let d = try parseBareDouble(
1095
18
                                source: body,
1096
18
                                index: &index,
1097
18
                                end: end
1098
18
                            ) {
1099
12
                                if index == end {
1100
0
                                    return d
1101
12
                                }
1102
15
                            }
1103
15
                        }
1104
15
                        return nil
1105
18
                    }
1106
0
                    if let n = n {
1107
0
                        return n
1108
0
                    }
1109
1
                }
1110
0
            }
1111
4
        } else {
1112
4
            if let d = try parseBareDouble(
1113
4
                source: source,
1114
4
                index: &index,
1115
4
                end: source.endIndex
1116
4
            ) {
1117
2
                return d
1118
2
            }
1119
0
        }
1120
0
        throw JSONDecodingError.malformedNumber
1121
5
    }
1122
1123
    /// Return the contents of the following quoted string,
1124
    /// or throw an error if the next token is not a string.
1125
801
    internal mutating func nextQuotedString() throws -> String {
1126
801
        skipWhitespace()
1127
801
        guard hasMoreContent else {
1128
0
            throw JSONDecodingError.truncated
1129
801
        }
1130
801
        let c = currentByte
1131
801
        if c != asciiDoubleQuote {
1132
18
            throw JSONDecodingError.malformedString
1133
783
        }
1134
783
        if let s = parseOptionalQuotedString() {
1135
774
            return s
1136
774
        } else {
1137
9
            throw JSONDecodingError.malformedString
1138
9
        }
1139
783
    }
1140
1141
    /// Return the contents of the following quoted string,
1142
    /// or nil if the next token is not a string.
1143
    /// This will only throw an error if the next token starts
1144
    /// out as a string but is malformed in some way.
1145
0
    internal mutating func nextOptionalQuotedString() throws -> String? {
1146
0
        skipWhitespace()
1147
0
        guard hasMoreContent else {
1148
0
            return nil
1149
0
        }
1150
0
        let c = currentByte
1151
0
        if c != asciiDoubleQuote {
1152
0
            return nil
1153
0
        }
1154
0
        return try nextQuotedString()
1155
0
    }
1156
1157
    /// Return a Data with the decoded contents of the
1158
    /// following base-64 string.
1159
    ///
1160
    /// Notes on Google's implementation:
1161
    ///  * Google's C++ implementation accepts arbitrary whitespace
1162
    ///    mixed in with the base-64 characters
1163
    ///  * Google's C++ implementation ignores missing '=' characters
1164
    ///    but if present, there must be the exact correct number of them.
1165
    ///  * Google's C++ implementation accepts both "regular" and
1166
    ///    "web-safe" base-64 variants (it seems to prefer the
1167
    ///    web-safe version as defined in RFC 4648
1168
0
    internal mutating func nextBytesValue() throws -> Data {
1169
0
        skipWhitespace()
1170
0
        guard hasMoreContent else {
1171
0
            throw JSONDecodingError.truncated
1172
0
        }
1173
0
        return try parseBytes(source: source, index: &index, end: source.endIndex)
1174
0
    }
1175
1176
    /// Private function to help parse keywords.
1177
62.0k
    private mutating func skipOptionalKeyword(bytes: [UInt8]) -> Bool {
1178
62.0k
        let start = index
1179
248k
        for b in bytes {
1180
248k
            guard hasMoreContent else {
1181
31
                index = start
1182
31
                return false
1183
248k
            }
1184
248k
            let c = currentByte
1185
248k
            if c != b {
1186
99
                index = start
1187
99
                return false
1188
248k
            }
1189
248k
            advance()
1190
248k
        }
1191
61.8k
        if hasMoreContent {
1192
61.8k
            let c = currentByte
1193
61.8k
            if (c >= asciiUpperA && c <= asciiUpperZ) || (c >= asciiLowerA && c <= asciiLowerZ) {
1194
24
                index = start
1195
24
                return false
1196
61.7k
            }
1197
61.8k
        }
1198
61.8k
        return true
1199
62.0k
    }
1200
1201
    /// If the next token is the identifier "null", consume it and return true.
1202
696
    internal mutating func skipOptionalNull() -> Bool {
1203
696
        skipWhitespace()
1204
332k
        if hasMoreContent && currentByte == asciiLowerN {
1205
4
            return skipOptionalKeyword(bytes: [
1206
4
                asciiLowerN, asciiLowerU, asciiLowerL, asciiLowerL,
1207
4
            ])
1208
692
        }
1209
692
        return false
1210
696
    }
1211
1212
    /// Return the following Bool "true" or "false", including
1213
    /// full processing of quoted boolean values.  (Used in map
1214
    /// keys, for instance.)
1215
0
    internal mutating func nextBool() throws -> Bool {
1216
0
        skipWhitespace()
1217
0
        guard hasMoreContent else {
1218
0
            throw JSONDecodingError.truncated
1219
0
        }
1220
0
        let c = currentByte
1221
0
        switch c {
1222
0
        case asciiLowerF:  // f
1223
0
            if skipOptionalKeyword(bytes: [
1224
0
                asciiLowerF, asciiLowerA, asciiLowerL, asciiLowerS, asciiLowerE,
1225
0
            ]) {
1226
0
                return false
1227
0
            }
1228
0
        case asciiLowerT:  // t
1229
0
            if skipOptionalKeyword(bytes: [
1230
0
                asciiLowerT, asciiLowerR, asciiLowerU, asciiLowerE,
1231
0
            ]) {
1232
0
                return true
1233
0
            }
1234
0
        default:
1235
0
            break
1236
0
        }
1237
0
        throw JSONDecodingError.malformedBool
1238
0
    }
1239
1240
    /// Return the following Bool "true" or "false", including
1241
    /// full processing of quoted boolean values.  (Used in map
1242
    /// keys, for instance.)
1243
0
    internal mutating func nextQuotedBool() throws -> Bool {
1244
0
        skipWhitespace()
1245
0
        guard hasMoreContent else {
1246
0
            throw JSONDecodingError.truncated
1247
0
        }
1248
0
        if currentByte != asciiDoubleQuote {
1249
0
            throw JSONDecodingError.unquotedMapKey
1250
0
        }
1251
0
        if let s = parseOptionalQuotedString() {
1252
0
            switch s {
1253
0
            case "false": return false
1254
0
            case "true": return true
1255
0
            default: break
1256
0
            }
1257
0
        }
1258
0
        throw JSONDecodingError.malformedBool
1259
0
    }
1260
1261
    /// Returns pointer/count spanning the UTF8 bytes of the next regular
1262
    /// key or nil if the key contains a backslash (and therefore requires
1263
    /// the full string-parsing logic to properly parse).
1264
829k
    private mutating func nextOptionalKey() throws -> UnsafeRawBufferPointer? {
1265
829k
        skipWhitespace()
1266
829k
        let stringStart = index
1267
829k
        guard hasMoreContent else {
1268
109
            throw JSONDecodingError.truncated
1269
829k
        }
1270
829k
        if currentByte != asciiDoubleQuote {
1271
385
            return nil
1272
829k
        }
1273
829k
        advance()
1274
829k
        let nameStart = index
1275
20.1M
        while hasMoreContent && currentByte != asciiDoubleQuote {
1276
19.3M
            if currentByte == asciiBackslash || currentByte < asciiSpace {
1277
60.0k
                // Backslash escapes go through the slow path; unescaped control
1278
60.0k
                // characters are invalid there and get rejected uniformly.
1279
60.0k
                index = stringStart  // Reset to open quote
1280
60.0k
                return nil
1281
19.2M
            }
1282
19.2M
            advance()
1283
19.2M
        }
1284
769k
        guard hasMoreContent else {
1285
650
            throw JSONDecodingError.truncated
1286
768k
        }
1287
768k
        let buff = UnsafeRawBufferPointer(
1288
768k
            start: source.baseAddress! + nameStart,
1289
768k
            count: index - nameStart
1290
768k
        )
1291
768k
        advance()
1292
768k
        return buff
1293
829k
    }
1294
1295
    /// Parse a field name, look it up in the provided field name map,
1296
    /// and return the corresponding field number.
1297
    ///
1298
    /// Throws if field name cannot be parsed.
1299
    /// If it encounters an unknown field name, it throws
1300
    /// unless `options.ignoreUnknownFields` is set, in which case
1301
    /// it silently skips it.
1302
    internal mutating func nextFieldNumber(
1303
        names: _NameMap,
1304
        messageType: any Message.Type
1305
118
    ) throws -> Int? {
1306
118
        while true {
1307
118
            var fieldName: String
1308
118
            if let key = try nextOptionalKey() {
1309
112
                // Fast path:  We parsed it as UTF8 bytes...
1310
112
                try skipRequiredCharacter(asciiColon)  // :
1311
112
                if let fieldNumber = names.number(forJSONName: key) {
1312
45
                    return fieldNumber
1313
67
                }
1314
67
                if let s = utf8ToString(bytes: key.baseAddress!, count: key.count) {
1315
67
                    fieldName = s
1316
67
                } else {
1317
0
                    throw JSONDecodingError.invalidUTF8
1318
67
                }
1319
67
            } else {
1320
6
                // Slow path:  We parsed a String; lookups from String are slower.
1321
6
                fieldName = try nextQuotedString()
1322
3
                try skipRequiredCharacter(asciiColon)  // :
1323
3
                if let fieldNumber = names.number(forJSONName: fieldName) {
1324
0
                    return fieldNumber
1325
3
                }
1326
70
            }
1327
70
            if let first = fieldName.utf8.first, first == UInt8(ascii: "["),
1328
70
                let last = fieldName.utf8.last, last == UInt8(ascii: "]")
1329
70
            {
1330
70
                fieldName.removeFirst()
1331
70
                fieldName.removeLast()
1332
70
                if let fieldNumber = extensions.fieldNumberForProto(messageType: messageType, protoFieldName: fieldName)
1333
70
                {
1334
0
                    return fieldNumber
1335
70
                }
1336
70
            }
1337
70
            if !options.ignoreUnknownFields {
1338
70
                throw JSONDecodingError.unknownField(fieldName)
1339
70
            }
1340
0
            // Unknown field, skip it and try to parse the next field name
1341
0
            try skipValue()
1342
0
            if skipOptionalObjectEnd() {
1343
0
                return nil
1344
0
            }
1345
0
            try skipRequiredComma()
1346
0
        }
1347
0
    }
1348
1349
    /// Parse the next token as a string or numeric enum value.  Throws
1350
    /// unrecognizedEnumValue if the string/number can't initialize the
1351
    /// enum.  Will throw other errors if the JSON is malformed.
1352
0
    internal mutating func nextEnumValue<E: Enum>() throws -> E? {
1353
6.90k
        func throwOrIgnore() throws -> E? {
1354
6.90k
            if options.ignoreUnknownFields {
1355
6.74k
                return nil
1356
6.74k
            } else {
1357
161
                throw JSONDecodingError.unrecognizedEnumValue
1358
161
            }
1359
6.90k
        }
1360
0
        skipWhitespace()
1361
0
        guard hasMoreContent else {
1362
0
            throw JSONDecodingError.truncated
1363
0
        }
1364
0
        if currentByte == asciiDoubleQuote {
1365
0
            if let name = try nextOptionalKey() {
1366
0
                if let e = E(rawUTF8: name) {
1367
0
                    return e
1368
0
                } else {
1369
0
                    return try throwOrIgnore()
1370
0
                }
1371
0
            }
1372
0
            let name = try nextQuotedString()
1373
0
            if let e = E(name: name) {
1374
0
                return e
1375
0
            } else {
1376
0
                return try throwOrIgnore()
1377
0
            }
1378
0
        } else {
1379
0
            let n = try nextSInt()
1380
0
            // Enum values are int32 on the wire; reject anything outside
1381
0
            // that range like the text format decoder does.
1382
18.0k
            guard n >= Int64(Int32.min) && n <= Int64(Int32.max) else {
1383
0
                throw JSONDecodingError.numberRange
1384
0
            }
1385
0
            if let e = E(rawValue: Int(n)) {
1386
0
                return e
1387
0
            } else {
1388
0
                return try throwOrIgnore()
1389
0
            }
1390
0
        }
1391
0
    }
1392
1393
    /// Helper for skipping a single-character token.
1394
2.28M
    private mutating func skipRequiredCharacter(_ required: UInt8) throws {
1395
2.28M
        skipWhitespace()
1396
2.28M
        guard hasMoreContent else {
1397
1.62k
            throw JSONDecodingError.truncated
1398
2.28M
        }
1399
2.28M
        let next = currentByte
1400
2.28M
        if next == required {
1401
2.28M
            advance()
1402
2.28M
            return
1403
2.28M
        }
1404
2.13k
        throw JSONDecodingError.failure
1405
2.28M
    }
1406
1407
    /// Skip "{", throw if that's not the next character.
1408
3.29k
    internal mutating func skipRequiredObjectStart() throws {
1409
3.29k
        try skipRequiredCharacter(asciiOpenCurlyBracket)  // {
1410
3.16k
        try incrementRecursionDepth()
1411
3.16k
    }
1412
1413
    /// Skip ",", throw if that's not the next character.
1414
1.44k
    internal mutating func skipRequiredComma() throws {
1415
1.44k
        try skipRequiredCharacter(asciiComma)
1416
1.44k
    }
1417
1418
    /// Skip ":", throw if that's not the next character.
1419
1.29k
    internal mutating func skipRequiredColon() throws {
1420
1.29k
        try skipRequiredCharacter(asciiColon)
1421
688
    }
1422
1423
    /// Skip "[", throw if that's not the next character.
1424
4
    internal mutating func skipRequiredArrayStart() throws {
1425
4
        try skipRequiredCharacter(asciiOpenSquareBracket)  // [
1426
4
    }
1427
1428
    /// Helper for skipping optional single-character tokens.
1429
2.71M
    private mutating func skipOptionalCharacter(_ c: UInt8) -> Bool {
1430
2.71M
        skipWhitespace()
1431
2.71M
        if hasMoreContent && currentByte == c {
1432
1.04M
            advance()
1433
1.04M
            return true
1434
1.67M
        }
1435
1.67M
        return false
1436
2.71M
    }
1437
1438
    /// If the next non-whitespace character is "[", skip it
1439
    /// and return true.  Otherwise, return false.
1440
0
    internal mutating func skipOptionalArrayStart() -> Bool {
1441
0
        skipOptionalCharacter(asciiOpenSquareBracket)
1442
0
    }
1443
1444
    /// If the next non-whitespace character is "]", skip it
1445
    /// and return true.  Otherwise, return false.
1446
18
    internal mutating func skipOptionalArrayEnd() -> Bool {
1447
18
        skipOptionalCharacter(asciiCloseSquareBracket)  // ]// ]
1448
18
    }
1449
1450
    /// If the next non-whitespace character is "}", skip it
1451
    /// and return true.  Otherwise, return false.
1452
8.97k
    internal mutating func skipOptionalObjectEnd() -> Bool {
1453
8.97k
        let result = skipOptionalCharacter(asciiCloseCurlyBracket)  // }
1454
8.97k
        if result {
1455
1.05k
            decrementRecursionDepth()
1456
1.05k
        }
1457
8.97k
        return result
1458
8.97k
    }
1459
1460
    /// Return the next complete JSON structure as a string.
1461
    /// For example, this might return "true", or "123.456",
1462
    /// or "{\"foo\": 7, \"bar\": [8, 9]}"
1463
    ///
1464
    /// Used by Any to get the upcoming JSON value as a string.
1465
    /// Note: The value might be an object or array.
1466
0
    internal mutating func skip() throws -> String {
1467
0
        skipWhitespace()
1468
0
        let start = index
1469
0
        try skipValue()
1470
0
        if let s = utf8ToString(bytes: source, start: start, end: index) {
1471
0
            return s
1472
0
        } else {
1473
0
            throw JSONDecodingError.invalidUTF8
1474
0
        }
1475
0
    }
1476
1477
    /// Advance index past the next value.  This is used
1478
    /// by skip() and by unknown field handling.
1479
    /// Note: This handles objects {...} recursively but arrays [...] non-recursively
1480
    /// This avoids us requiring excessive stack space for deeply nested
1481
    /// arrays (which are not included in the recursion budget check).
1482
630k
    private mutating func skipValue() throws {
1483
630k
        skipWhitespace()
1484
630k
        var totalArrayDepth = 0
1485
658k
        while true {
1486
658k
            var arrayDepth = 0
1487
1.18M
            while skipOptionalArrayStart() {
1488
526k
                arrayDepth += 1
1489
658k
            }
1490
658k
            guard hasMoreContent else {
1491
130
                throw JSONDecodingError.truncated
1492
658k
            }
1493
658k
            switch currentByte {
1494
658k
            case asciiDoubleQuote:  // " begins a string
1495
11.0k
                try skipString()
1496
658k
            case asciiOpenCurlyBracket:  // { begins an object
1497
376k
                try skipObject()
1498
658k
            case asciiCloseSquareBracket:  // ] ends an empty array
1499
7.86k
                if arrayDepth == 0 {
1500
3
                    throw JSONDecodingError.failure
1501
7.86k
                }
1502
7.86k
                // We also close out [[]] or [[[]]] here
1503
17.8k
                while arrayDepth > 0 && skipOptionalArrayEnd() {
1504
10.0k
                    arrayDepth -= 1
1505
10.0k
                }
1506
658k
            case asciiLowerN:  // n must be null
1507
29.4k
                if !skipOptionalKeyword(bytes: [
1508
29.4k
                    asciiLowerN, asciiLowerU, asciiLowerL, asciiLowerL,
1509
29.4k
                ]) {
1510
15
                    throw JSONDecodingError.truncated
1511
15
                }
1512
658k
            case asciiLowerF:  // f must be false
1513
333
                if !skipOptionalKeyword(bytes: [
1514
333
                    asciiLowerF, asciiLowerA, asciiLowerL, asciiLowerS, asciiLowerE,
1515
333
                ]) {
1516
13
                    throw JSONDecodingError.truncated
1517
13
                }
1518
658k
            case asciiLowerT:  // t must be true
1519
211
                if !skipOptionalKeyword(bytes: [
1520
211
                    asciiLowerT, asciiLowerR, asciiLowerU, asciiLowerE,
1521
211
                ]) {
1522
13
                    throw JSONDecodingError.truncated
1523
13
                }
1524
658k
            default:  // everything else is a number token
1525
232k
                _ = try nextDouble()
1526
658k
            }
1527
657k
            totalArrayDepth += arrayDepth
1528
667k
            while totalArrayDepth > 0 && skipOptionalArrayEnd() {
1529
9.69k
                totalArrayDepth -= 1
1530
657k
            }
1531
657k
            if totalArrayDepth > 0 {
1532
28.0k
                try skipRequiredComma()
1533
629k
            } else {
1534
629k
                return
1535
629k
            }
1536
28.0k
        }
1537
0
    }
1538
1539
    /// Advance the index past the next complete {...} construct.
1540
376k
    private mutating func skipObject() throws {
1541
376k
        try skipRequiredObjectStart()
1542
376k
        if skipOptionalObjectEnd() {
1543
366k
            return
1544
366k
        }
1545
45.0k
        while true {
1546
45.0k
            skipWhitespace()
1547
45.0k
            try skipString()
1548
44.9k
            try skipRequiredColon()
1549
44.9k
            try skipValue()
1550
44.4k
            if skipOptionalObjectEnd() {
1551
9.63k
                return
1552
34.8k
            }
1553
34.8k
            try skipRequiredComma()
1554
34.8k
        }
1555
0
    }
1556
1557
    /// Advance the index past the next complete quoted string.
1558
    ///
1559
    // Caveat:  This does not fully validate; it will accept
1560
    // strings that have malformed \ escapes.
1561
    //
1562
    // It would be nice to do better, but I don't think it's critical,
1563
    // since there are many reasons that strings (and other tokens for
1564
    // that matter) may be skippable but not parsable.  For example:
1565
    // Old clients that don't know new field types will skip fields
1566
    // they don't know; newer clients may reject the same input due to
1567
    // schema mismatches or other issues.
1568
56.0k
    private mutating func skipString() throws {
1569
56.0k
        guard hasMoreContent else {
1570
15
            throw JSONDecodingError.truncated
1571
56.0k
        }
1572
56.0k
        if currentByte != asciiDoubleQuote {
1573
61
            throw JSONDecodingError.malformedString
1574
55.9k
        }
1575
55.9k
        advance()
1576
1.16M
        while hasMoreContent {
1577
1.16M
            let c = currentByte
1578
1.16M
            switch c {
1579
1.16M
            case asciiDoubleQuote:
1580
55.9k
                advance()
1581
55.9k
                return
1582
1.16M
            case asciiBackslash:
1583
4.83k
                advance()
1584
4.83k
                guard hasMoreContent else {
1585
1
                    throw JSONDecodingError.truncated
1586
4.83k
                }
1587
4.83k
                advance()
1588
1.16M
            default:
1589
1.09M
                advance()
1590
1.16M
            }
1591
1.10M
        }
1592
67
        throw JSONDecodingError.truncated
1593
56.0k
    }
1594
}