Coverage Report

Created: 2026-06-30 06:42

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
61.5k
private func fromHexDigit(_ c: UnicodeScalar) -> UInt32? {
71
61.5k
    let n = c.value
72
61.5k
    if n >= 48 && n <= 57 {
73
54.7k
        return UInt32(n - 48)
74
54.7k
    }
75
6.82k
    switch n {
76
6.82k
    case 65, 97: return 10
77
6.82k
    case 66, 98: return 11
78
6.82k
    case 67, 99: return 12
79
6.82k
    case 68, 100: return 13
80
6.82k
    case 69, 101: return 14
81
6.82k
    case 70, 102: return 15
82
6.82k
    default:
83
75
        return nil
84
6.82k
    }
85
6.82k
}
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
12.6k
) throws -> Data {
128
12.6k
    let c = source[index]
129
12.6k
    if c != asciiDoubleQuote {
130
26
        throw JSONDecodingError.malformedString
131
12.6k
    }
132
12.6k
    source.formIndex(after: &index)
133
12.6k
134
12.6k
    // Count the base-64 digits
135
12.6k
    // Ignore most unrecognized characters in this first pass,
136
12.6k
    // stop at the closing double quote.
137
12.6k
    let digitsStart = index
138
12.6k
    var rawChars = 0
139
12.6k
    var sawSection4Characters = false
140
12.6k
    var sawSection5Characters = false
141
10.6M
    while index != end {
142
10.6M
        var digit = source[index]
143
10.6M
        if digit == asciiDoubleQuote {
144
12.5k
            break
145
10.6M
        }
146
10.6M
147
10.6M
        if digit == asciiBackslash {
148
277
            source.formIndex(after: &index)
149
277
            if index == end {
150
2
                throw JSONDecodingError.malformedString
151
275
            }
152
275
            let escaped = source[index]
153
275
            switch escaped {
154
275
            case asciiLowerU:
155
2
                // TODO: Parse hex escapes such as \u0041.  Note that
156
2
                // such escapes are going to be extremely rare, so
157
2
                // there's little point in optimizing for them.
158
2
                throw JSONDecodingError.malformedString
159
275
            case asciiForwardSlash:
160
270
                digit = escaped
161
275
            default:
162
3
                // Reject \b \f \n \r \t \" or \\ and all illegal escapes
163
3
                throw JSONDecodingError.malformedString
164
275
            }
165
10.6M
        }
166
10.6M
167
10.6M
        if digit == asciiPlus || digit == asciiForwardSlash {
168
4.31k
            sawSection4Characters = true
169
10.6M
        } else if digit == asciiMinus || digit == asciiUnderscore {
170
3.77k
            sawSection5Characters = true
171
3.77k
        }
172
10.6M
        let k = base64Values[Int(digit)]
173
10.6M
        if k >= 0 {
174
10.3M
            rawChars += 1
175
10.3M
        }
176
10.6M
        source.formIndex(after: &index)
177
10.6M
    }
178
12.6k
179
12.6k
    // We reached the end without seeing the close quote
180
12.6k
    if index == end {
181
85
        throw JSONDecodingError.malformedString
182
12.5k
    }
183
12.5k
    // Reject mixed encodings.
184
12.5k
    if sawSection4Characters && sawSection5Characters {
185
4
        throw JSONDecodingError.malformedString
186
12.5k
    }
187
12.5k
188
12.5k
    // Allocate a Data object of exactly the right size
189
12.5k
    var value = Data(count: rawChars * 3 / 4)
190
12.5k
191
12.5k
    // Scan the digits again and populate the Data object.
192
12.5k
    // In this pass, we check for (and fail) if there are
193
12.5k
    // unexpected characters.  But we don't check for end-of-input,
194
12.5k
    // because the loop above already verified that there was
195
12.5k
    // a closing double quote.
196
12.5k
    index = digitsStart
197
12.5k
    try value.withUnsafeMutableBytes {
198
12.5k
        (body: UnsafeMutableRawBufferPointer) in
199
12.5k
        if var p = body.baseAddress, body.count > 0 {
200
6.03k
            var n = 0
201
6.03k
            var chars = 0  // # chars in current group
202
6.03k
            var padding = 0  // # padding '=' chars
203
8.66M
            digits: while true {
204
8.66M
                let digit = source[index]
205
8.66M
                var k = base64Values[Int(digit)]
206
8.66M
                if k < 0 {
207
137k
                    switch digit {
208
137k
                    case asciiDoubleQuote:
209
5.66k
                        break digits
210
137k
                    case asciiBackslash:
211
122
                        source.formIndex(after: &index)
212
122
                        let escaped = source[index]
213
122
                        switch escaped {
214
122
                        case asciiForwardSlash:
215
122
                            k = base64Values[Int(escaped)]
216
122
                        default:
217
0
                            // Note: Invalid backslash escapes were caught
218
0
                            // above; we should never get here.
219
0
                            throw JSONDecodingError.malformedString
220
122
                        }
221
137k
                    case asciiSpace:
222
130k
                        source.formIndex(after: &index)
223
130k
                        continue digits
224
137k
                    case asciiEqualSign:  // Count padding
225
26.0k
                        while true {
226
26.0k
                            switch source[index] {
227
26.0k
                            case asciiDoubleQuote:
228
318
                                break digits
229
26.0k
                            case asciiSpace:
230
24.0k
                                break
231
26.0k
                            case 61:
232
1.70k
                                padding += 1
233
26.0k
                            default:  // Only '=' and whitespace permitted
234
25
                                throw JSONDecodingError.malformedString
235
26.0k
                            }
236
25.7k
                            source.formIndex(after: &index)
237
25.7k
                        }
238
137k
                    default:
239
23
                        throw JSONDecodingError.malformedString
240
137k
                    }
241
8.53M
                }
242
8.53M
                n <<= 6
243
8.53M
                n |= k
244
8.53M
                chars += 1
245
8.53M
                if chars == 4 {
246
2.13M
                    p[0] = UInt8(truncatingIfNeeded: n >> 16)
247
2.13M
                    p[1] = UInt8(truncatingIfNeeded: n >> 8)
248
2.13M
                    p[2] = UInt8(truncatingIfNeeded: n)
249
2.13M
                    p += 3
250
2.13M
                    chars = 0
251
2.13M
                    n = 0
252
2.13M
                }
253
8.53M
                source.formIndex(after: &index)
254
8.53M
            }
255
5.98k
            switch chars {
256
5.98k
            case 3:
257
1.58k
                p[0] = UInt8(truncatingIfNeeded: n >> 10)
258
1.58k
                p[1] = UInt8(truncatingIfNeeded: n >> 2)
259
1.58k
                if padding == 1 || padding == 0 {
260
1.58k
                    return
261
1.58k
                }
262
5.98k
            case 2:
263
2.23k
                p[0] = UInt8(truncatingIfNeeded: n >> 4)
264
2.23k
                if padding == 2 || padding == 0 {
265
2.22k
                    return
266
2.22k
                }
267
5.98k
            case 0:
268
2.14k
                if padding == 0 {
269
2.14k
                    return
270
2.14k
                }
271
5.98k
            default:
272
12
                break
273
5.98k
            }
274
30
            throw JSONDecodingError.malformedString
275
6.48k
        }
276
12.4k
    }
277
12.4k
    source.formIndex(after: &index)
278
12.4k
    return value
279
12.6k
}
280
281
// JSON encoding allows a variety of \-escapes, including
282
// escaping UTF-16 code points (which may be surrogate pairs).
283
14.9k
private func decodeString(_ s: String) -> String? {
284
14.9k
    var out = String.UnicodeScalarView()
285
14.9k
    var chars = s.unicodeScalars.makeIterator()
286
1.20M
    while let c = chars.next() {
287
1.20M
        switch c.value {
288
1.20M
        case UInt32(asciiBackslash):  // backslash
289
17.4k
            if let escaped = chars.next() {
290
17.4k
                switch escaped.value {
291
17.4k
                case UInt32(asciiLowerU):  // "\u"
292
14.9k
                    // Exactly 4 hex digits:
293
14.9k
                    if let digit1 = chars.next(),
294
14.9k
                        let d1 = fromHexDigit(digit1),
295
14.9k
                        let digit2 = chars.next(),
296
14.9k
                        let d2 = fromHexDigit(digit2),
297
14.9k
                        let digit3 = chars.next(),
298
14.9k
                        let d3 = fromHexDigit(digit3),
299
14.9k
                        let digit4 = chars.next(),
300
14.9k
                        let d4 = fromHexDigit(digit4)
301
14.9k
                    {
302
14.7k
                        let codePoint = ((d1 * 16 + d2) * 16 + d3) * 16 + d4
303
14.7k
                        if let scalar = UnicodeScalar(codePoint) {
304
14.1k
                            out.append(scalar)
305
14.1k
                        } else if codePoint < 0xD800 || codePoint >= 0xE000 {
306
0
                            // Not a valid Unicode scalar.
307
0
                            return nil
308
605
                        } else if codePoint >= 0xDC00 {
309
15
                            // Low surrogate without a preceding high surrogate.
310
15
                            return nil
311
590
                        } else {
312
590
                            // We have a high surrogate (in the range 0xD800..<0xDC00), so
313
590
                            // verify that it is followed by a low surrogate.
314
590
                            guard chars.next() == "\\", chars.next() == "u" else {
315
57
                                // High surrogate was not followed by a Unicode escape sequence.
316
57
                                return nil
317
533
                            }
318
533
                            if let digit1 = chars.next(),
319
533
                                let d1 = fromHexDigit(digit1),
320
533
                                let digit2 = chars.next(),
321
533
                                let d2 = fromHexDigit(digit2),
322
533
                                let digit3 = chars.next(),
323
533
                                let d3 = fromHexDigit(digit3),
324
533
                                let digit4 = chars.next(),
325
533
                                let d4 = fromHexDigit(digit4)
326
533
                            {
327
507
                                let follower = ((d1 * 16 + d2) * 16 + d3) * 16 + d4
328
507
                                guard 0xDC00 <= follower && follower < 0xE000 else {
329
26
                                    // High surrogate was not followed by a low surrogate.
330
26
                                    return nil
331
481
                                }
332
481
                                let high = codePoint - 0xD800
333
481
                                let low = follower - 0xDC00
334
481
                                let composed = 0x10000 | high << 10 | low
335
481
                                guard let composedScalar = UnicodeScalar(composed) else {
336
0
                                    // Composed value is not a valid Unicode scalar.
337
0
                                    return nil
338
481
                                }
339
481
                                out.append(composedScalar)
340
481
                            } else {
341
26
                                // Malformed \u escape for low surrogate
342
26
                                return nil
343
481
                            }
344
14.6k
                        }
345
14.6k
                    } else {
346
162
                        // Malformed \u escape
347
162
                        return nil
348
162
                    }
349
17.4k
                case UInt32(asciiLowerB):  // \b
350
123
                    out.append("\u{08}")
351
17.4k
                case UInt32(asciiLowerF):  // \f
352
110
                    out.append("\u{0c}")
353
17.4k
                case UInt32(asciiLowerN):  // \n
354
135
                    out.append("\u{0a}")
355
17.4k
                case UInt32(asciiLowerR):  // \r
356
178
                    out.append("\u{0d}")
357
17.4k
                case UInt32(asciiLowerT):  // \t
358
241
                    out.append("\u{09}")
359
17.4k
                case UInt32(asciiDoubleQuote), UInt32(asciiBackslash),
360
1.65k
                    UInt32(asciiForwardSlash):  // " \ /
361
1.65k
                    out.append(escaped)
362
17.4k
                default:
363
69
                    return nil  // Unrecognized escape
364
17.4k
                }
365
17.1k
            } else {
366
0
                return nil  // Input ends with backslash
367
0
            }
368
1.20M
        default:
369
1.19M
            out.append(c)
370
1.20M
        }
371
1.20M
    }
372
14.6k
    return String(out)
373
14.9k
}
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
206k
    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
58.6k
        mutating get {
392
58.6k
            skipWhitespace()
393
58.6k
            return !hasMoreContent
394
58.6k
        }
395
    }
396
397
    /// True if the scanner has not yet reached the end of the source.
398
2.21G
    private var hasMoreContent: Bool {
399
2.21G
        index != source.endIndex
400
2.21G
    }
401
402
    /// The byte (UTF-8 code unit) at the scanner's current position.
403
2.75G
    private var currentByte: UInt8 {
404
2.75G
        source[index]
405
2.75G
    }
406
407
    internal init(
408
        source: UnsafeRawBufferPointer,
409
        options: JSONDecodingOptions,
410
        extensions: (any ExtensionMap)?
411
199k
    ) {
412
199k
        self.source = source
413
199k
        self.index = source.startIndex
414
199k
        self.recursionBudget = options.messageDepthLimit
415
199k
        self.options = options
416
199k
        self.extensions = extensions ?? SimpleExtensionMap()
417
199k
    }
418
419
4.91M
    internal mutating func incrementRecursionDepth() throws {
420
4.91M
        recursionBudget -= 1
421
4.91M
        if recursionBudget < 0 {
422
225
            throw JSONDecodingError.messageDepthLimit
423
4.91M
        }
424
4.91M
    }
425
426
6.03M
    internal mutating func decrementRecursionDepth() {
427
6.03M
        recursionBudget += 1
428
6.03M
        // This should never happen, if it does, something is probably corrupting memory, and
429
6.03M
        // simply throwing doesn't make much sense.
430
6.03M
        if recursionBudget > options.messageDepthLimit {
431
0
            fatalError("Somehow JSONDecoding unwound more objects than it started")
432
0
        }
433
6.03M
    }
434
435
    /// Advances the scanner to the next position in the source.
436
306M
    private mutating func advance() {
437
306M
        source.formIndex(after: &index)
438
306M
    }
439
440
    /// Skip whitespace.
441
150M
    private mutating func skipWhitespace() {
442
204M
        while hasMoreContent {
443
204M
            let u = currentByte
444
204M
            switch u {
445
204M
            case asciiSpace, asciiTab, asciiNewLine, asciiCarriageReturn:
446
54.3M
                advance()
447
204M
            default:
448
150M
                return
449
204M
            }
450
54.3M
        }
451
218k
    }
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
522k
    internal mutating func peekOneCharacter() throws -> Character {
457
522k
        skipWhitespace()
458
522k
        guard hasMoreContent else {
459
43
            throw JSONDecodingError.truncated
460
522k
        }
461
522k
        return Character(UnicodeScalar(UInt32(currentByte))!)
462
522k
    }
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
358k
    ) throws -> UInt64? {
496
358k
        if index == end {
497
22
            throw JSONDecodingError.truncated
498
358k
        }
499
358k
        let start = index
500
358k
        let c = source[index]
501
358k
        switch c {
502
358k
        case asciiZero:  // 0
503
214k
            source.formIndex(after: &index)
504
214k
            if index != end {
505
213k
                let after = source[index]
506
213k
                switch after {
507
213k
                case asciiZero...asciiNine:  // 0...9
508
5
                    // leading '0' forbidden unless it is the only digit
509
5
                    throw JSONDecodingError.leadingZero
510
213k
                case asciiPeriod, asciiLowerE, asciiUpperE:  // . e
511
1.78k
                    // Slow path: JSON numbers can be written in floating-point notation
512
1.78k
                    index = start
513
1.78k
                    if let d = try parseBareDouble(
514
1.78k
                        source: source,
515
1.78k
                        index: &index,
516
1.78k
                        end: end
517
1.78k
                    ) {
518
1.75k
                        if let u = UInt64(exactly: d) {
519
1.74k
                            return u
520
1.74k
                        }
521
4
                    }
522
4
                    throw JSONDecodingError.malformedNumber
523
213k
                case asciiBackslash:
524
812
                    return nil
525
213k
                default:
526
211k
                    return 0
527
213k
                }
528
213k
            }
529
251
            return 0
530
358k
        case asciiOne...asciiNine:  // 1...9
531
142k
            var n = 0 as UInt64
532
357k
            while index != end {
533
355k
                let digit = source[index]
534
355k
                switch digit {
535
355k
                case asciiZero...asciiNine:  // 0...9
536
215k
                    let val = UInt64(digit - asciiZero)
537
215k
                    if n > UInt64.max / 10 || n * 10 > UInt64.max - val {
538
8
                        throw JSONDecodingError.numberRange
539
215k
                    }
540
215k
                    source.formIndex(after: &index)
541
215k
                    n = n * 10 + val
542
355k
                case asciiPeriod, asciiLowerE, asciiUpperE:  // . e
543
2.80k
                    // Slow path: JSON allows floating-point notation for integers
544
2.80k
                    index = start
545
2.80k
                    if let d = try parseBareDouble(
546
2.80k
                        source: source,
547
2.80k
                        index: &index,
548
2.80k
                        end: end
549
2.80k
                    ) {
550
2.75k
                        if let u = UInt64(exactly: d) {
551
2.74k
                            return u
552
2.74k
                        }
553
11
                    }
554
11
                    throw JSONDecodingError.malformedNumber
555
355k
                case asciiBackslash:
556
574
                    return nil
557
355k
                default:
558
137k
                    return n
559
355k
                }
560
215k
            }
561
1.97k
            return n
562
358k
        case asciiBackslash:
563
1.03k
            return nil
564
358k
        default:
565
195
            throw JSONDecodingError.malformedNumber
566
358k
        }
567
358k
    }
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
240k
    ) throws -> Int64? {
585
240k
        if index == end {
586
40
            throw JSONDecodingError.truncated
587
240k
        }
588
240k
        let c = source[index]
589
240k
        if c == asciiMinus {  // -
590
15.4k
            source.formIndex(after: &index)
591
15.4k
            if index == end {
592
7
                throw JSONDecodingError.truncated
593
15.3k
            }
594
15.3k
            // character after '-' must be digit
595
15.3k
            let digit = source[index]
596
15.3k
            if digit < asciiZero || digit > asciiNine {
597
13
                throw JSONDecodingError.malformedNumber
598
15.3k
            }
599
15.3k
            if let n = try parseBareUInt64(source: source, index: &index, end: end) {
600
14.8k
                let limit: UInt64 = 0x8000_0000_0000_0000  // -Int64.min
601
14.8k
                if n >= limit {
602
309
                    if n > limit {
603
100
                        // Too large negative number
604
100
                        throw JSONDecodingError.numberRange
605
209
                    } else {
606
209
                        return Int64.min  // Special case for Int64.min
607
209
                    }
608
14.5k
                }
609
14.5k
                return -Int64(bitPattern: n)
610
14.8k
            } else {
611
484
                return nil
612
484
            }
613
225k
        } else if let n = try parseBareUInt64(source: source, index: &index, end: end) {
614
223k
            if n > UInt64(bitPattern: Int64.max) {
615
104
                throw JSONDecodingError.numberRange
616
223k
            }
617
223k
            return Int64(bitPattern: n)
618
223k
        } else {
619
1.24k
            return nil
620
1.24k
        }
621
240k
    }
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
2.02M
    ) throws -> Double? {
639
2.02M
        // RFC 7159 defines the grammar for JSON numbers as:
640
2.02M
        // number = [ minus ] int [ frac ] [ exp ]
641
2.02M
        if index == end {
642
8
            throw JSONDecodingError.truncated
643
2.02M
        }
644
2.02M
        let start = index
645
2.02M
        var c = source[index]
646
2.02M
        if c == asciiBackslash {
647
1.12k
            return nil
648
2.01M
        }
649
2.01M
650
2.01M
        // Optional leading minus sign
651
2.01M
        if c == asciiMinus {  // -
652
8.58k
            source.formIndex(after: &index)
653
8.58k
            if index == end {
654
4
                index = start
655
4
                throw JSONDecodingError.truncated
656
8.58k
            }
657
8.58k
            c = source[index]
658
8.58k
            if c == asciiBackslash {
659
543
                return nil
660
8.03k
            }
661
2.01M
        } else if c == asciiUpperN {  // Maybe NaN?
662
1.41k
            // Return nil, let the caller deal with it.
663
1.41k
            return nil
664
2.01M
        }
665
2.01M
666
2.01M
        if c == asciiUpperI {  // Maybe Infinity, Inf, -Infinity, or -Inf ?
667
3.23k
            // Return nil, let the caller deal with it.
668
3.23k
            return nil
669
2.01M
        }
670
2.01M
671
2.01M
        // Integer part can be zero or a series of digits not starting with zero
672
2.01M
        // int = zero / (digit1-9 *DIGIT)
673
2.01M
        switch c {
674
2.01M
        case asciiZero:
675
1.58M
            // First digit can be zero only if not followed by a digit
676
1.58M
            source.formIndex(after: &index)
677
1.58M
            if index == end {
678
537
                return 0.0
679
1.58M
            }
680
1.58M
            c = source[index]
681
1.58M
            if c == asciiBackslash {
682
181
                return nil
683
1.58M
            }
684
1.58M
            if c >= asciiZero && c <= asciiNine {
685
9
                throw JSONDecodingError.leadingZero
686
9
            }
687
2.01M
        case asciiOne...asciiNine:
688
1.01M
            while c >= asciiZero && c <= asciiNine {
689
588k
                source.formIndex(after: &index)
690
588k
                if index == end {
691
1.18k
                    if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
692
1.18k
                        return d
693
1.18k
                    } else {
694
4
                        throw JSONDecodingError.invalidUTF8
695
4
                    }
696
587k
                }
697
587k
                c = source[index]
698
587k
                if c == asciiBackslash {
699
327
                    return nil
700
587k
                }
701
587k
            }
702
2.01M
        default:
703
271
            // Integer part cannot be empty
704
271
            throw JSONDecodingError.malformedNumber
705
2.01M
        }
706
2.01M
707
2.01M
        // frac = decimal-point 1*DIGIT
708
2.01M
        if c == asciiPeriod {
709
15.7k
            source.formIndex(after: &index)
710
15.7k
            if index == end {
711
16
                // decimal point must have a following digit
712
16
                throw JSONDecodingError.truncated
713
15.7k
            }
714
15.7k
            c = source[index]
715
15.7k
            switch c {
716
15.7k
            case asciiZero...asciiNine:  // 0...9
717
1.08M
                while c >= asciiZero && c <= asciiNine {
718
1.07M
                    source.formIndex(after: &index)
719
1.07M
                    if index == end {
720
1.43k
                        if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
721
1.42k
                            return d
722
1.42k
                        } else {
723
4
                            throw JSONDecodingError.invalidUTF8
724
4
                        }
725
1.07M
                    }
726
1.07M
                    c = source[index]
727
1.07M
                    if c == asciiBackslash {
728
610
                        return nil
729
1.07M
                    }
730
1.07M
                }
731
15.7k
            case asciiBackslash:
732
415
                return nil
733
15.7k
            default:
734
22
                // decimal point must be followed by at least one digit
735
22
                throw JSONDecodingError.malformedNumber
736
15.7k
            }
737
2.00M
        }
738
2.00M
739
2.00M
        // exp = e [ minus / plus ] 1*DIGIT
740
2.00M
        if c == asciiLowerE || c == asciiUpperE {
741
20.8k
            source.formIndex(after: &index)
742
20.8k
            if index == end {
743
49
                // "e" must be followed by +,-, or digit
744
49
                throw JSONDecodingError.truncated
745
20.7k
            }
746
20.7k
            c = source[index]
747
20.7k
            if c == asciiBackslash {
748
247
                return nil
749
20.5k
            }
750
20.5k
            if c == asciiPlus || c == asciiMinus {  // + -
751
15.5k
                source.formIndex(after: &index)
752
15.5k
                if index == end {
753
15
                    // must be at least one digit in exponent
754
15
                    throw JSONDecodingError.truncated
755
15.5k
                }
756
15.5k
                c = source[index]
757
15.5k
                if c == asciiBackslash {
758
531
                    return nil
759
14.9k
                }
760
19.9k
            }
761
19.9k
            switch c {
762
19.9k
            case asciiZero...asciiNine:
763
945k
                while c >= asciiZero && c <= asciiNine {
764
941k
                    source.formIndex(after: &index)
765
941k
                    if index == end {
766
9.33k
                        if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
767
9.31k
                            return d
768
9.31k
                        } else {
769
21
                            throw JSONDecodingError.invalidUTF8
770
21
                        }
771
932k
                    }
772
932k
                    c = source[index]
773
932k
                    if c == asciiBackslash {
774
7.13k
                        return nil
775
925k
                    }
776
925k
                }
777
19.9k
            default:
778
45
                // must be at least one digit in exponent
779
45
                throw JSONDecodingError.malformedNumber
780
19.9k
            }
781
1.99M
        }
782
1.99M
        if let d = numberParser.utf8ToDouble(bytes: source, start: start, end: index) {
783
1.99M
            return d
784
1.99M
        } else {
785
28
            throw JSONDecodingError.invalidUTF8
786
28
        }
787
1.99M
    }
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
53.0k
    private mutating func parseOptionalQuotedString() -> String? {
794
53.0k
        // Caller has already asserted that currentByte == quote here
795
53.0k
        var sawBackslash = false
796
53.0k
        advance()
797
53.0k
        let start = index
798
8.07M
        while hasMoreContent {
799
8.07M
            switch currentByte {
800
8.07M
            case asciiDoubleQuote:  // "
801
45.7k
                let s = utf8ToString(bytes: source, start: start, end: index)
802
45.7k
                advance()
803
45.7k
                if let t = s {
804
45.7k
                    if sawBackslash {
805
14.9k
                        return decodeString(t)
806
30.7k
                    } else {
807
30.7k
                        return t
808
30.7k
                    }
809
45.7k
                } else {
810
38
                    return nil  // Invalid UTF8
811
38
                }
812
8.07M
            case asciiBackslash:  //  \
813
19.1k
                advance()
814
19.1k
                guard hasMoreContent else {
815
32
                    return nil  // Unterminated escape
816
19.0k
                }
817
19.0k
                sawBackslash = true
818
8.07M
            case 0..<asciiSpace:
819
7.13k
                // Unescaped control characters (U+0000...U+001F) are not
820
7.13k
                // allowed inside a JSON string; they must be escaped.
821
7.13k
                return nil
822
8.07M
            default:
823
8.00M
                break
824
8.07M
            }
825
8.02M
            advance()
826
8.02M
        }
827
77
        return nil  // Unterminated quoted string
828
53.0k
    }
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
106k
    internal mutating func nextUInt() throws -> UInt64 {
838
106k
        skipWhitespace()
839
106k
        guard hasMoreContent else {
840
40
            throw JSONDecodingError.truncated
841
106k
        }
842
106k
        let c = currentByte
843
106k
        if c == asciiDoubleQuote {
844
12.2k
            let start = index
845
12.2k
            advance()
846
12.2k
            if let u = try parseBareUInt64(
847
12.2k
                source: source,
848
12.2k
                index: &index,
849
12.2k
                end: source.endIndex
850
12.2k
            ) {
851
11.6k
                guard hasMoreContent else {
852
3
                    throw JSONDecodingError.truncated
853
11.6k
                }
854
11.6k
                if currentByte != asciiDoubleQuote {
855
12
                    throw JSONDecodingError.malformedNumber
856
11.6k
                }
857
11.6k
                advance()
858
11.6k
                return u
859
11.6k
            } else {
860
577
                // Couldn't parse because it had a "\" in the string,
861
577
                // so parse out the quoted string and then reparse
862
577
                // the result to get a UInt.
863
577
                index = start
864
577
                let s = try nextQuotedString()
865
553
                let raw = s.data(using: String.Encoding.utf8)!
866
659
                let n = try raw.withUnsafeBytes {
867
659
                    (body: UnsafeRawBufferPointer) -> UInt64? in
868
659
                    if body.count > 0 {
869
659
                        var index = body.startIndex
870
659
                        let end = body.endIndex
871
659
                        if let u = try parseBareUInt64(
872
659
                            source: body,
873
659
                            index: &index,
874
659
                            end: end
875
659
                        ) {
876
651
                            if index == end {
877
642
                                return u
878
642
                            }
879
14
                        }
880
14
                    }
881
14
                    return nil
882
659
                }
883
550
                if let n = n {
884
539
                    return n
885
539
                }
886
11
            }
887
11
        } else if let u = try parseBareUInt64(
888
106k
            source: source,
889
106k
            index: &index,
890
106k
            end: source.endIndex
891
106k
        ) {
892
93.8k
            return u
893
93.8k
        }
894
14
        throw JSONDecodingError.malformedNumber
895
106k
    }
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
215k
    internal mutating func nextSInt() throws -> Int64 {
904
215k
        skipWhitespace()
905
215k
        guard hasMoreContent else {
906
61
            throw JSONDecodingError.truncated
907
215k
        }
908
215k
        let c = currentByte
909
215k
        if c == asciiDoubleQuote {
910
20.1k
            let start = index
911
20.1k
            advance()
912
20.1k
            if let s = try parseBareSInt64(
913
20.1k
                source: source,
914
20.1k
                index: &index,
915
20.1k
                end: source.endIndex
916
20.1k
            ) {
917
18.7k
                guard hasMoreContent else {
918
4
                    throw JSONDecodingError.truncated
919
18.7k
                }
920
18.7k
                if currentByte != asciiDoubleQuote {
921
6
                    throw JSONDecodingError.malformedNumber
922
18.7k
                }
923
18.7k
                advance()
924
18.7k
                return s
925
18.7k
            } else {
926
1.28k
                // Couldn't parse because it had a "\" in the string,
927
1.28k
                // so parse out the quoted string and then reparse
928
1.28k
                // the result as an SInt.
929
1.28k
                index = start
930
1.28k
                let s = try nextQuotedString()
931
1.24k
                let raw = s.data(using: String.Encoding.utf8)!
932
1.65k
                let n = try raw.withUnsafeBytes {
933
1.65k
                    (body: UnsafeRawBufferPointer) -> Int64? in
934
1.65k
                    if body.count > 0 {
935
1.65k
                        var index = body.startIndex
936
1.65k
                        let end = body.endIndex
937
1.65k
                        if let s = try parseBareSInt64(
938
1.65k
                            source: body,
939
1.65k
                            index: &index,
940
1.65k
                            end: end
941
1.65k
                        ) {
942
1.61k
                            if index == end {
943
1.58k
                                return s
944
1.58k
                            }
945
44
                        }
946
44
                    }
947
44
                    return nil
948
1.65k
                }
949
1.22k
                if let n = n {
950
1.18k
                    return n
951
1.18k
                }
952
41
            }
953
41
        } else if let s = try parseBareSInt64(
954
215k
            source: source,
955
215k
            index: &index,
956
215k
            end: source.endIndex
957
215k
        ) {
958
194k
            return s
959
194k
        }
960
49
        throw JSONDecodingError.malformedNumber
961
215k
    }
962
963
    /// Parse the next Float value, regardless of whether it
964
    /// is quoted, including handling backslash escapes for
965
    /// quoted strings.
966
1.45M
    internal mutating func nextFloat() throws -> Float {
967
1.45M
        skipWhitespace()
968
1.45M
        guard hasMoreContent else {
969
20
            throw JSONDecodingError.truncated
970
1.45M
        }
971
1.45M
        let c = currentByte
972
1.45M
        if c == asciiDoubleQuote {  // "
973
11.2k
            let start = index
974
11.2k
            advance()
975
11.2k
            if let d = try parseBareDouble(
976
11.2k
                source: source,
977
11.2k
                index: &index,
978
11.2k
                end: source.endIndex
979
11.2k
            ) {
980
1.42k
                guard hasMoreContent else {
981
1
                    throw JSONDecodingError.truncated
982
1.42k
                }
983
1.42k
                if currentByte != asciiDoubleQuote {
984
12
                    throw JSONDecodingError.malformedNumber
985
1.41k
                }
986
1.41k
                advance()
987
1.41k
                // A value that parses as a finite Double can still be out of
988
1.41k
                // range for Float (for example "1e39"), in which case the
989
1.41k
                // conversion yields an infinity. Reject it, matching the
990
1.41k
                // unquoted path below.
991
1.41k
                let f = Float(d)
992
1.41k
                if f.isFinite {
993
1.40k
                    return f
994
1.40k
                }
995
1
                throw JSONDecodingError.malformedNumber
996
9.84k
            } else {
997
9.84k
                // Slow Path: parseBareDouble returned nil: It might be
998
9.84k
                // a valid float, but had something that
999
9.84k
                // parseBareDouble cannot directly handle.  So we reset,
1000
9.84k
                // try a full string parse, then examine the result:
1001
9.84k
                index = start
1002
9.84k
                let s = try nextQuotedString()
1003
9.69k
                switch s {
1004
9.69k
                case "NaN": return Float.nan
1005
9.69k
                case "Inf": return Float.infinity
1006
9.69k
                case "-Inf": return -Float.infinity
1007
9.69k
                case "Infinity": return Float.infinity
1008
9.69k
                case "-Infinity": return -Float.infinity
1009
9.69k
                default:
1010
8.79k
                    let raw = s.data(using: String.Encoding.utf8)!
1011
9.82k
                    let n = try raw.withUnsafeBytes {
1012
9.82k
                        (body: UnsafeRawBufferPointer) -> Float? in
1013
9.82k
                        if body.count > 0 {
1014
9.82k
                            var index = body.startIndex
1015
9.82k
                            let end = body.endIndex
1016
9.82k
                            if let d = try parseBareDouble(
1017
9.82k
                                source: body,
1018
9.82k
                                index: &index,
1019
9.82k
                                end: end
1020
9.82k
                            ) {
1021
9.59k
                                let f = Float(d)
1022
9.59k
                                if index == end && f.isFinite {
1023
9.56k
                                    return f
1024
9.56k
                                }
1025
229
                            }
1026
229
                        }
1027
229
                        return nil
1028
9.82k
                    }
1029
8.76k
                    if let n = n {
1030
8.55k
                        return n
1031
8.55k
                    }
1032
9.69k
                }
1033
207
            }
1034
1.44M
        } else {
1035
1.44M
            if let d = try parseBareDouble(
1036
1.44M
                source: source,
1037
1.44M
                index: &index,
1038
1.44M
                end: source.endIndex
1039
1.44M
            ) {
1040
1.44M
                let f = Float(d)
1041
1.44M
                if f.isFinite {
1042
1.44M
                    return f
1043
1.44M
                }
1044
9
            }
1045
216
        }
1046
216
        throw JSONDecodingError.malformedNumber
1047
1.45M
    }
1048
1049
    /// Parse the next Double value, regardless of whether it
1050
    /// is quoted, including handling backslash escapes for
1051
    /// quoted strings.
1052
530k
    internal mutating func nextDouble() throws -> Double {
1053
530k
        skipWhitespace()
1054
530k
        guard hasMoreContent else {
1055
21
            throw JSONDecodingError.truncated
1056
530k
        }
1057
530k
        let c = currentByte
1058
530k
        if c == asciiDoubleQuote {  // "
1059
3.48k
            let start = index
1060
3.48k
            advance()
1061
3.48k
            if let d = try parseBareDouble(
1062
3.48k
                source: source,
1063
3.48k
                index: &index,
1064
3.48k
                end: source.endIndex
1065
3.48k
            ) {
1066
412
                guard hasMoreContent else {
1067
2
                    throw JSONDecodingError.truncated
1068
410
                }
1069
410
                if currentByte != asciiDoubleQuote {
1070
11
                    throw JSONDecodingError.malformedNumber
1071
399
                }
1072
399
                advance()
1073
399
                return d
1074
3.05k
            } else {
1075
3.05k
                // Slow Path: parseBareDouble returned nil: It might be
1076
3.05k
                // a valid float, but had something that
1077
3.05k
                // parseBareDouble cannot directly handle.  So we reset,
1078
3.05k
                // try a full string parse, then examine the result:
1079
3.05k
                index = start
1080
3.05k
                let s = try nextQuotedString()
1081
2.90k
                switch s {
1082
2.90k
                case "NaN": return Double.nan
1083
2.90k
                case "Inf": return Double.infinity
1084
2.90k
                case "-Inf": return -Double.infinity
1085
2.90k
                case "Infinity": return Double.infinity
1086
2.90k
                case "-Infinity": return -Double.infinity
1087
2.90k
                default:
1088
1.03k
                    let raw = s.data(using: String.Encoding.utf8)!
1089
1.40k
                    let n = try raw.withUnsafeBytes {
1090
1.40k
                        (body: UnsafeRawBufferPointer) -> Double? in
1091
1.40k
                        if body.count > 0 {
1092
1.40k
                            var index = body.startIndex
1093
1.40k
                            let end = body.endIndex
1094
1.40k
                            if let d = try parseBareDouble(
1095
1.40k
                                source: body,
1096
1.40k
                                index: &index,
1097
1.40k
                                end: end
1098
1.40k
                            ) {
1099
1.21k
                                if index == end {
1100
1.19k
                                    return d
1101
1.19k
                                }
1102
180
                            }
1103
180
                        }
1104
180
                        return nil
1105
1.40k
                    }
1106
1.01k
                    if let n = n {
1107
838
                        return n
1108
838
                    }
1109
2.90k
                }
1110
175
            }
1111
526k
        } else {
1112
526k
            if let d = try parseBareDouble(
1113
526k
                source: source,
1114
526k
                index: &index,
1115
526k
                end: source.endIndex
1116
526k
            ) {
1117
526k
                return d
1118
526k
            }
1119
193
        }
1120
193
        throw JSONDecodingError.malformedNumber
1121
530k
    }
1122
1123
    /// Return the contents of the following quoted string,
1124
    /// or throw an error if the next token is not a string.
1125
359k
    internal mutating func nextQuotedString() throws -> String {
1126
359k
        skipWhitespace()
1127
359k
        guard hasMoreContent else {
1128
486
            throw JSONDecodingError.truncated
1129
359k
        }
1130
359k
        let c = currentByte
1131
359k
        if c != asciiDoubleQuote {
1132
2.82k
            throw JSONDecodingError.malformedString
1133
356k
        }
1134
356k
        if let s = parseOptionalQuotedString() {
1135
296k
            return s
1136
296k
        } else {
1137
59.6k
            throw JSONDecodingError.malformedString
1138
59.6k
        }
1139
356k
    }
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
32.5k
    internal mutating func nextBytesValue() throws -> Data {
1169
32.5k
        skipWhitespace()
1170
32.5k
        guard hasMoreContent else {
1171
84
            throw JSONDecodingError.truncated
1172
32.4k
        }
1173
32.4k
        return try parseBytes(source: source, index: &index, end: source.endIndex)
1174
32.5k
    }
1175
1176
    /// Private function to help parse keywords.
1177
39.4k
    private mutating func skipOptionalKeyword(bytes: [UInt8]) -> Bool {
1178
39.4k
        let start = index
1179
160k
        for b in bytes {
1180
160k
            guard hasMoreContent else {
1181
101
                index = start
1182
101
                return false
1183
160k
            }
1184
160k
            let c = currentByte
1185
160k
            if c != b {
1186
98
                index = start
1187
98
                return false
1188
160k
            }
1189
160k
            advance()
1190
160k
        }
1191
39.2k
        if hasMoreContent {
1192
38.7k
            let c = currentByte
1193
38.7k
            if (c >= asciiUpperA && c <= asciiUpperZ) || (c >= asciiLowerA && c <= asciiLowerZ) {
1194
21
                index = start
1195
21
                return false
1196
38.7k
            }
1197
39.2k
        }
1198
39.2k
        return true
1199
39.4k
    }
1200
1201
    /// If the next token is the identifier "null", consume it and return true.
1202
1.31M
    internal mutating func skipOptionalNull() -> Bool {
1203
1.31M
        skipWhitespace()
1204
1.45M
        if hasMoreContent && currentByte == asciiLowerN {
1205
50.7k
            return skipOptionalKeyword(bytes: [
1206
50.7k
                asciiLowerN, asciiLowerU, asciiLowerL, asciiLowerL,
1207
50.7k
            ])
1208
1.26M
        }
1209
1.26M
        return false
1210
1.31M
    }
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
7.92k
    internal mutating func nextBool() throws -> Bool {
1216
7.92k
        skipWhitespace()
1217
7.92k
        guard hasMoreContent else {
1218
25
            throw JSONDecodingError.truncated
1219
7.90k
        }
1220
7.90k
        let c = currentByte
1221
7.90k
        switch c {
1222
7.90k
        case asciiLowerF:  // f
1223
1.33k
            if skipOptionalKeyword(bytes: [
1224
1.33k
                asciiLowerF, asciiLowerA, asciiLowerL, asciiLowerS, asciiLowerE,
1225
1.33k
            ]) {
1226
1.33k
                return false
1227
1.33k
            }
1228
7.90k
        case asciiLowerT:  // t
1229
6.53k
            if skipOptionalKeyword(bytes: [
1230
6.53k
                asciiLowerT, asciiLowerR, asciiLowerU, asciiLowerE,
1231
6.53k
            ]) {
1232
6.52k
                return true
1233
6.52k
            }
1234
7.90k
        default:
1235
30
            break
1236
7.90k
        }
1237
51
        throw JSONDecodingError.malformedBool
1238
7.92k
    }
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
1.33k
    internal mutating func nextQuotedBool() throws -> Bool {
1244
1.33k
        skipWhitespace()
1245
1.33k
        guard hasMoreContent else {
1246
0
            throw JSONDecodingError.truncated
1247
1.33k
        }
1248
1.33k
        if currentByte != asciiDoubleQuote {
1249
0
            throw JSONDecodingError.unquotedMapKey
1250
1.33k
        }
1251
1.33k
        if let s = parseOptionalQuotedString() {
1252
1.21k
            switch s {
1253
1.21k
            case "false": return false
1254
1.21k
            case "true": return true
1255
1.21k
            default: break
1256
1.21k
            }
1257
189
        }
1258
189
        throw JSONDecodingError.malformedBool
1259
1.33k
    }
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
262k
    private mutating func nextOptionalKey() throws -> UnsafeRawBufferPointer? {
1265
262k
        skipWhitespace()
1266
262k
        let stringStart = index
1267
262k
        guard hasMoreContent else {
1268
246
            throw JSONDecodingError.truncated
1269
261k
        }
1270
261k
        if currentByte != asciiDoubleQuote {
1271
356
            return nil
1272
261k
        }
1273
261k
        advance()
1274
261k
        let nameStart = index
1275
5.81M
        while hasMoreContent && currentByte != asciiDoubleQuote {
1276
5.55M
            if currentByte == asciiBackslash || currentByte < asciiSpace {
1277
4.96k
                // Backslash escapes go through the slow path; unescaped control
1278
4.96k
                // characters are invalid there and get rejected uniformly.
1279
4.96k
                index = stringStart  // Reset to open quote
1280
4.96k
                return nil
1281
5.55M
            }
1282
5.55M
            advance()
1283
5.55M
        }
1284
256k
        guard hasMoreContent else {
1285
432
            throw JSONDecodingError.truncated
1286
256k
        }
1287
256k
        let buff = UnsafeRawBufferPointer(
1288
256k
            start: source.baseAddress! + nameStart,
1289
256k
            count: index - nameStart
1290
256k
        )
1291
256k
        advance()
1292
256k
        return buff
1293
262k
    }
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
172k
    ) throws -> Int? {
1306
191k
        while true {
1307
191k
            var fieldName: String
1308
191k
            if let key = try nextOptionalKey() {
1309
187k
                // Fast path:  We parsed it as UTF8 bytes...
1310
187k
                try skipRequiredCharacter(asciiColon)  // :
1311
187k
                if let fieldNumber = names.number(forJSONName: key) {
1312
97.9k
                    return fieldNumber
1313
97.9k
                }
1314
89.3k
                if let s = utf8ToString(bytes: key.baseAddress!, count: key.count) {
1315
89.2k
                    fieldName = s
1316
89.2k
                } else {
1317
49
                    throw JSONDecodingError.invalidUTF8
1318
89.2k
                }
1319
89.2k
            } else {
1320
3.69k
                // Slow path:  We parsed a String; lookups from String are slower.
1321
3.69k
                fieldName = try nextQuotedString()
1322
369
                try skipRequiredCharacter(asciiColon)  // :
1323
203
                if let fieldNumber = names.number(forJSONName: fieldName) {
1324
54
                    return fieldNumber
1325
149
                }
1326
89.4k
            }
1327
89.4k
            if let first = fieldName.utf8.first, first == UInt8(ascii: "["),
1328
89.4k
                let last = fieldName.utf8.last, last == UInt8(ascii: "]")
1329
89.4k
            {
1330
42.2k
                fieldName.removeFirst()
1331
42.2k
                fieldName.removeLast()
1332
42.2k
                if let fieldNumber = extensions.fieldNumberForProto(messageType: messageType, protoFieldName: fieldName)
1333
42.2k
                {
1334
32.7k
                    return fieldNumber
1335
32.7k
                }
1336
56.6k
            }
1337
56.6k
            if !options.ignoreUnknownFields {
1338
214
                throw JSONDecodingError.unknownField(fieldName)
1339
56.3k
            }
1340
56.3k
            // Unknown field, skip it and try to parse the next field name
1341
56.3k
            try skipValue()
1342
55.9k
            if skipOptionalObjectEnd() {
1343
37.3k
                return nil
1344
37.3k
            }
1345
18.6k
            try skipRequiredComma()
1346
18.5k
        }
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
11.5k
    internal mutating func nextEnumValue<E: Enum>() throws -> E? {
1353
11.5k
        func throwOrIgnore() throws -> E? {
1354
3.76k
            if options.ignoreUnknownFields {
1355
3.53k
                return nil
1356
3.53k
            } else {
1357
223
                throw JSONDecodingError.unrecognizedEnumValue
1358
223
            }
1359
3.76k
        }
1360
11.5k
        skipWhitespace()
1361
11.5k
        guard hasMoreContent else {
1362
18
            throw JSONDecodingError.truncated
1363
11.5k
        }
1364
11.5k
        if currentByte == asciiDoubleQuote {
1365
432
            if let name = try nextOptionalKey() {
1366
64
                if let e = E(rawUTF8: name) {
1367
0
                    return e
1368
64
                } else {
1369
64
                    return try throwOrIgnore()
1370
64
                }
1371
364
            }
1372
364
            let name = try nextQuotedString()
1373
360
            if let e = E(name: name) {
1374
0
                return e
1375
360
            } else {
1376
360
                return try throwOrIgnore()
1377
360
            }
1378
11.1k
        } else {
1379
11.1k
            let n = try nextSInt()
1380
10.9k
            if let i = Int(exactly: n) {
1381
10.9k
                if let e = E(rawValue: i) {
1382
8.86k
                    return e
1383
8.86k
                } else {
1384
2.04k
                    return try throwOrIgnore()
1385
2.04k
                }
1386
10.9k
            } else {
1387
0
                throw JSONDecodingError.numberRange
1388
0
            }
1389
10.9k
        }
1390
11.5k
    }
1391
1392
    /// Helper for skipping a single-character token.
1393
11.6M
    private mutating func skipRequiredCharacter(_ required: UInt8) throws {
1394
11.6M
        skipWhitespace()
1395
11.6M
        guard hasMoreContent else {
1396
13.2k
            throw JSONDecodingError.truncated
1397
11.6M
        }
1398
11.6M
        let next = currentByte
1399
11.6M
        if next == required {
1400
11.6M
            advance()
1401
11.6M
            return
1402
11.6M
        }
1403
5.47k
        throw JSONDecodingError.failure
1404
11.6M
    }
1405
1406
    /// Skip "{", throw if that's not the next character.
1407
3.11M
    internal mutating func skipRequiredObjectStart() throws {
1408
3.11M
        try skipRequiredCharacter(asciiOpenCurlyBracket)  // {
1409
3.09M
        try incrementRecursionDepth()
1410
3.09M
    }
1411
1412
    /// Skip ",", throw if that's not the next character.
1413
85.8M
    internal mutating func skipRequiredComma() throws {
1414
85.8M
        try skipRequiredCharacter(asciiComma)
1415
85.7M
    }
1416
1417
    /// Skip ":", throw if that's not the next character.
1418
767k
    internal mutating func skipRequiredColon() throws {
1419
767k
        try skipRequiredCharacter(asciiColon)
1420
766k
    }
1421
1422
    /// Skip "[", throw if that's not the next character.
1423
144k
    internal mutating func skipRequiredArrayStart() throws {
1424
144k
        try skipRequiredCharacter(asciiOpenSquareBracket)  // [
1425
143k
    }
1426
1427
    /// Helper for skipping optional single-character tokens.
1428
75.2M
    private mutating func skipOptionalCharacter(_ c: UInt8) -> Bool {
1429
75.2M
        skipWhitespace()
1430
75.2M
        if hasMoreContent && currentByte == c {
1431
5.71M
            advance()
1432
5.71M
            return true
1433
69.4M
        }
1434
69.4M
        return false
1435
75.2M
    }
1436
1437
    /// If the next non-whitespace character is "[", skip it
1438
    /// and return true.  Otherwise, return false.
1439
91.6k
    internal mutating func skipOptionalArrayStart() -> Bool {
1440
91.6k
        skipOptionalCharacter(asciiOpenSquareBracket)
1441
91.6k
    }
1442
1443
    /// If the next non-whitespace character is "]", skip it
1444
    /// and return true.  Otherwise, return false.
1445
21.3M
    internal mutating func skipOptionalArrayEnd() -> Bool {
1446
21.3M
        skipOptionalCharacter(asciiCloseSquareBracket)  // ]// ]
1447
21.3M
    }
1448
1449
    /// If the next non-whitespace character is "}", skip it
1450
    /// and return true.  Otherwise, return false.
1451
13.2M
    internal mutating func skipOptionalObjectEnd() -> Bool {
1452
13.2M
        let result = skipOptionalCharacter(asciiCloseCurlyBracket)  // }
1453
13.2M
        if result {
1454
4.14M
            decrementRecursionDepth()
1455
4.14M
        }
1456
13.2M
        return result
1457
13.2M
    }
1458
1459
    /// Return the next complete JSON structure as a string.
1460
    /// For example, this might return "true", or "123.456",
1461
    /// or "{\"foo\": 7, \"bar\": [8, 9]}"
1462
    ///
1463
    /// Used by Any to get the upcoming JSON value as a string.
1464
    /// Note: The value might be an object or array.
1465
862
    internal mutating func skip() throws -> String {
1466
862
        skipWhitespace()
1467
862
        let start = index
1468
862
        try skipValue()
1469
729
        if let s = utf8ToString(bytes: source, start: start, end: index) {
1470
726
            return s
1471
726
        } else {
1472
3
            throw JSONDecodingError.invalidUTF8
1473
3
        }
1474
729
    }
1475
1476
    /// Advance index past the next value.  This is used
1477
    /// by skip() and by unknown field handling.
1478
    /// Note: This handles objects {...} recursively but arrays [...] non-recursively
1479
    /// This avoids us requiring excessive stack space for deeply nested
1480
    /// arrays (which are not included in the recursion budget check).
1481
83.0k
    private mutating func skipValue() throws {
1482
83.0k
        skipWhitespace()
1483
83.0k
        var totalArrayDepth = 0
1484
92.2k
        while true {
1485
92.2k
            var arrayDepth = 0
1486
119k
            while skipOptionalArrayStart() {
1487
27.0k
                arrayDepth += 1
1488
92.2k
            }
1489
92.2k
            guard hasMoreContent else {
1490
241
                throw JSONDecodingError.truncated
1491
91.9k
            }
1492
91.9k
            switch currentByte {
1493
91.9k
            case asciiDoubleQuote:  // " begins a string
1494
20.6k
                try skipString()
1495
91.9k
            case asciiOpenCurlyBracket:  // { begins an object
1496
21.6k
                try skipObject()
1497
91.9k
            case asciiCloseSquareBracket:  // ] ends an empty array
1498
2.73k
                if arrayDepth == 0 {
1499
8
                    throw JSONDecodingError.failure
1500
2.73k
                }
1501
2.73k
                // We also close out [[]] or [[[]]] here
1502
5.84k
                while arrayDepth > 0 && skipOptionalArrayEnd() {
1503
3.11k
                    arrayDepth -= 1
1504
3.11k
                }
1505
91.9k
            case asciiLowerN:  // n must be null
1506
8.18k
                if !skipOptionalKeyword(bytes: [
1507
8.18k
                    asciiLowerN, asciiLowerU, asciiLowerL, asciiLowerL,
1508
8.18k
                ]) {
1509
22
                    throw JSONDecodingError.truncated
1510
22
                }
1511
91.9k
            case asciiLowerF:  // f must be false
1512
1.96k
                if !skipOptionalKeyword(bytes: [
1513
1.96k
                    asciiLowerF, asciiLowerA, asciiLowerL, asciiLowerS, asciiLowerE,
1514
1.96k
                ]) {
1515
12
                    throw JSONDecodingError.truncated
1516
12
                }
1517
91.9k
            case asciiLowerT:  // t must be true
1518
1.05k
                if !skipOptionalKeyword(bytes: [
1519
1.05k
                    asciiLowerT, asciiLowerR, asciiLowerU, asciiLowerE,
1520
1.05k
                ]) {
1521
13
                    throw JSONDecodingError.truncated
1522
13
                }
1523
91.9k
            default:  // everything else is a number token
1524
35.7k
                _ = try nextDouble()
1525
91.9k
            }
1526
91.2k
            totalArrayDepth += arrayDepth
1527
105k
            while totalArrayDepth > 0 && skipOptionalArrayEnd() {
1528
13.9k
                totalArrayDepth -= 1
1529
91.2k
            }
1530
91.2k
            if totalArrayDepth > 0 {
1531
9.33k
                try skipRequiredComma()
1532
81.9k
            } else {
1533
81.9k
                return
1534
81.9k
            }
1535
9.19k
        }
1536
0
    }
1537
1538
    /// Advance the index past the next complete {...} construct.
1539
21.6k
    private mutating func skipObject() throws {
1540
21.6k
        try skipRequiredObjectStart()
1541
21.6k
        if skipOptionalObjectEnd() {
1542
10.0k
            return
1543
11.5k
        }
1544
14.5k
        while true {
1545
14.5k
            skipWhitespace()
1546
14.5k
            try skipString()
1547
14.4k
            try skipRequiredColon()
1548
14.4k
            try skipValue()
1549
14.1k
            if skipOptionalObjectEnd() {
1550
11.2k
                return
1551
11.2k
            }
1552
2.97k
            try skipRequiredComma()
1553
2.97k
        }
1554
0
    }
1555
1556
    /// Advance the index past the next complete quoted string.
1557
    ///
1558
    // Caveat:  This does not fully validate; it will accept
1559
    // strings that have malformed \ escapes.
1560
    //
1561
    // It would be nice to do better, but I don't think it's critical,
1562
    // since there are many reasons that strings (and other tokens for
1563
    // that matter) may be skippable but not parsable.  For example:
1564
    // Old clients that don't know new field types will skip fields
1565
    // they don't know; newer clients may reject the same input due to
1566
    // schema mismatches or other issues.
1567
35.1k
    private mutating func skipString() throws {
1568
35.1k
        guard hasMoreContent else {
1569
33
            throw JSONDecodingError.truncated
1570
35.1k
        }
1571
35.1k
        if currentByte != asciiDoubleQuote {
1572
25
            throw JSONDecodingError.malformedString
1573
35.1k
        }
1574
35.1k
        advance()
1575
1.04M
        while hasMoreContent {
1576
1.04M
            let c = currentByte
1577
1.04M
            switch c {
1578
1.04M
            case asciiDoubleQuote:
1579
35.0k
                advance()
1580
35.0k
                return
1581
1.04M
            case asciiBackslash:
1582
342
                advance()
1583
342
                guard hasMoreContent else {
1584
3
                    throw JSONDecodingError.truncated
1585
339
                }
1586
339
                advance()
1587
1.04M
            default:
1588
1.00M
                advance()
1589
1.04M
            }
1590
1.00M
        }
1591
56
        throw JSONDecodingError.truncated
1592
35.1k
    }
1593
}