diff options
author | 2025-03-09 17:47:56 +0100 | |
---|---|---|
committer | 2025-03-10 01:59:49 +0100 | |
commit | 3ac1ee16f377d31a0fb80c8dae28b6239ac4229e (patch) | |
tree | f61faa581feaaeaba2542b9f2b8234a590684413 /vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go | |
parent | [chore] update URLs to forked source (diff) | |
download | gotosocial-3ac1ee16f377d31a0fb80c8dae28b6239ac4229e.tar.xz |
[chore] remove vendor
Diffstat (limited to 'vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go')
-rw-r--r-- | vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go | 528 |
1 files changed, 0 insertions, 528 deletions
diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go deleted file mode 100644 index 43f3e4f38..000000000 --- a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner.go +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (C) MongoDB, Inc. 2017-present. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -package bsonrw - -import ( - "bytes" - "errors" - "fmt" - "io" - "math" - "strconv" - "unicode" - "unicode/utf16" -) - -type jsonTokenType byte - -const ( - jttBeginObject jsonTokenType = iota - jttEndObject - jttBeginArray - jttEndArray - jttColon - jttComma - jttInt32 - jttInt64 - jttDouble - jttString - jttBool - jttNull - jttEOF -) - -type jsonToken struct { - t jsonTokenType - v interface{} - p int -} - -type jsonScanner struct { - r io.Reader - buf []byte - pos int - lastReadErr error -} - -// nextToken returns the next JSON token if one exists. A token is a character -// of the JSON grammar, a number, a string, or a literal. -func (js *jsonScanner) nextToken() (*jsonToken, error) { - c, err := js.readNextByte() - - // keep reading until a non-space is encountered (break on read error or EOF) - for isWhiteSpace(c) && err == nil { - c, err = js.readNextByte() - } - - if errors.Is(err, io.EOF) { - return &jsonToken{t: jttEOF}, nil - } else if err != nil { - return nil, err - } - - // switch on the character - switch c { - case '{': - return &jsonToken{t: jttBeginObject, v: byte('{'), p: js.pos - 1}, nil - case '}': - return &jsonToken{t: jttEndObject, v: byte('}'), p: js.pos - 1}, nil - case '[': - return &jsonToken{t: jttBeginArray, v: byte('['), p: js.pos - 1}, nil - case ']': - return &jsonToken{t: jttEndArray, v: byte(']'), p: js.pos - 1}, nil - case ':': - return &jsonToken{t: jttColon, v: byte(':'), p: js.pos - 1}, nil - case ',': - return &jsonToken{t: jttComma, v: byte(','), p: js.pos - 1}, nil - case '"': // RFC-8259 only allows for double quotes (") not single (') - return js.scanString() - default: - // check if it's a number - if c == '-' || isDigit(c) { - return js.scanNumber(c) - } else if c == 't' || c == 'f' || c == 'n' { - // maybe a literal - return js.scanLiteral(c) - } else { - return nil, fmt.Errorf("invalid JSON input. Position: %d. Character: %c", js.pos-1, c) - } - } -} - -// readNextByte attempts to read the next byte from the buffer. If the buffer -// has been exhausted, this function calls readIntoBuf, thus refilling the -// buffer and resetting the read position to 0 -func (js *jsonScanner) readNextByte() (byte, error) { - if js.pos >= len(js.buf) { - err := js.readIntoBuf() - - if err != nil { - return 0, err - } - } - - b := js.buf[js.pos] - js.pos++ - - return b, nil -} - -// readNNextBytes reads n bytes into dst, starting at offset -func (js *jsonScanner) readNNextBytes(dst []byte, n, offset int) error { - var err error - - for i := 0; i < n; i++ { - dst[i+offset], err = js.readNextByte() - if err != nil { - return err - } - } - - return nil -} - -// readIntoBuf reads up to 512 bytes from the scanner's io.Reader into the buffer -func (js *jsonScanner) readIntoBuf() error { - if js.lastReadErr != nil { - js.buf = js.buf[:0] - js.pos = 0 - return js.lastReadErr - } - - if cap(js.buf) == 0 { - js.buf = make([]byte, 0, 512) - } - - n, err := js.r.Read(js.buf[:cap(js.buf)]) - if err != nil { - js.lastReadErr = err - if n > 0 { - err = nil - } - } - js.buf = js.buf[:n] - js.pos = 0 - - return err -} - -func isWhiteSpace(c byte) bool { - return c == ' ' || c == '\t' || c == '\r' || c == '\n' -} - -func isDigit(c byte) bool { - return unicode.IsDigit(rune(c)) -} - -func isValueTerminator(c byte) bool { - return c == ',' || c == '}' || c == ']' || isWhiteSpace(c) -} - -// getu4 decodes the 4-byte hex sequence from the beginning of s, returning the hex value as a rune, -// or it returns -1. Note that the "\u" from the unicode escape sequence should not be present. -// It is copied and lightly modified from the Go JSON decode function at -// https://github.com/golang/go/blob/1b0a0316802b8048d69da49dc23c5a5ab08e8ae8/src/encoding/json/decode.go#L1169-L1188 -func getu4(s []byte) rune { - if len(s) < 4 { - return -1 - } - var r rune - for _, c := range s[:4] { - switch { - case '0' <= c && c <= '9': - c = c - '0' - case 'a' <= c && c <= 'f': - c = c - 'a' + 10 - case 'A' <= c && c <= 'F': - c = c - 'A' + 10 - default: - return -1 - } - r = r*16 + rune(c) - } - return r -} - -// scanString reads from an opening '"' to a closing '"' and handles escaped characters -func (js *jsonScanner) scanString() (*jsonToken, error) { - var b bytes.Buffer - var c byte - var err error - - p := js.pos - 1 - - for { - c, err = js.readNextByte() - if err != nil { - if errors.Is(err, io.EOF) { - return nil, errors.New("end of input in JSON string") - } - return nil, err - } - - evalNextChar: - switch c { - case '\\': - c, err = js.readNextByte() - if err != nil { - if errors.Is(err, io.EOF) { - return nil, errors.New("end of input in JSON string") - } - return nil, err - } - - evalNextEscapeChar: - switch c { - case '"', '\\', '/': - b.WriteByte(c) - case 'b': - b.WriteByte('\b') - case 'f': - b.WriteByte('\f') - case 'n': - b.WriteByte('\n') - case 'r': - b.WriteByte('\r') - case 't': - b.WriteByte('\t') - case 'u': - us := make([]byte, 4) - err = js.readNNextBytes(us, 4, 0) - if err != nil { - return nil, fmt.Errorf("invalid unicode sequence in JSON string: %s", us) - } - - rn := getu4(us) - - // If the rune we just decoded is the high or low value of a possible surrogate pair, - // try to decode the next sequence as the low value of a surrogate pair. We're - // expecting the next sequence to be another Unicode escape sequence (e.g. "\uDD1E"), - // but need to handle cases where the input is not a valid surrogate pair. - // For more context on unicode surrogate pairs, see: - // https://www.christianfscott.com/rust-chars-vs-go-runes/ - // https://www.unicode.org/glossary/#high_surrogate_code_point - if utf16.IsSurrogate(rn) { - c, err = js.readNextByte() - if err != nil { - if errors.Is(err, io.EOF) { - return nil, errors.New("end of input in JSON string") - } - return nil, err - } - - // If the next value isn't the beginning of a backslash escape sequence, write - // the Unicode replacement character for the surrogate value and goto the - // beginning of the next char eval block. - if c != '\\' { - b.WriteRune(unicode.ReplacementChar) - goto evalNextChar - } - - c, err = js.readNextByte() - if err != nil { - if errors.Is(err, io.EOF) { - return nil, errors.New("end of input in JSON string") - } - return nil, err - } - - // If the next value isn't the beginning of a unicode escape sequence, write the - // Unicode replacement character for the surrogate value and goto the beginning - // of the next escape char eval block. - if c != 'u' { - b.WriteRune(unicode.ReplacementChar) - goto evalNextEscapeChar - } - - err = js.readNNextBytes(us, 4, 0) - if err != nil { - return nil, fmt.Errorf("invalid unicode sequence in JSON string: %s", us) - } - - rn2 := getu4(us) - - // Try to decode the pair of runes as a utf16 surrogate pair. If that fails, write - // the Unicode replacement character for the surrogate value and the 2nd decoded rune. - if rnPair := utf16.DecodeRune(rn, rn2); rnPair != unicode.ReplacementChar { - b.WriteRune(rnPair) - } else { - b.WriteRune(unicode.ReplacementChar) - b.WriteRune(rn2) - } - - break - } - - b.WriteRune(rn) - default: - return nil, fmt.Errorf("invalid escape sequence in JSON string '\\%c'", c) - } - case '"': - return &jsonToken{t: jttString, v: b.String(), p: p}, nil - default: - b.WriteByte(c) - } - } -} - -// scanLiteral reads an unquoted sequence of characters and determines if it is one of -// three valid JSON literals (true, false, null); if so, it returns the appropriate -// jsonToken; otherwise, it returns an error -func (js *jsonScanner) scanLiteral(first byte) (*jsonToken, error) { - p := js.pos - 1 - - lit := make([]byte, 4) - lit[0] = first - - err := js.readNNextBytes(lit, 3, 1) - if err != nil { - return nil, err - } - - c5, err := js.readNextByte() - - if bytes.Equal([]byte("true"), lit) && (isValueTerminator(c5) || errors.Is(err, io.EOF)) { - js.pos = int(math.Max(0, float64(js.pos-1))) - return &jsonToken{t: jttBool, v: true, p: p}, nil - } else if bytes.Equal([]byte("null"), lit) && (isValueTerminator(c5) || errors.Is(err, io.EOF)) { - js.pos = int(math.Max(0, float64(js.pos-1))) - return &jsonToken{t: jttNull, v: nil, p: p}, nil - } else if bytes.Equal([]byte("fals"), lit) { - if c5 == 'e' { - c5, err = js.readNextByte() - - if isValueTerminator(c5) || errors.Is(err, io.EOF) { - js.pos = int(math.Max(0, float64(js.pos-1))) - return &jsonToken{t: jttBool, v: false, p: p}, nil - } - } - } - - return nil, fmt.Errorf("invalid JSON literal. Position: %d, literal: %s", p, lit) -} - -type numberScanState byte - -const ( - nssSawLeadingMinus numberScanState = iota - nssSawLeadingZero - nssSawIntegerDigits - nssSawDecimalPoint - nssSawFractionDigits - nssSawExponentLetter - nssSawExponentSign - nssSawExponentDigits - nssDone - nssInvalid -) - -// scanNumber reads a JSON number (according to RFC-8259) -func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) { - var b bytes.Buffer - var s numberScanState - var c byte - var err error - - t := jttInt64 // assume it's an int64 until the type can be determined - start := js.pos - 1 - - b.WriteByte(first) - - switch first { - case '-': - s = nssSawLeadingMinus - case '0': - s = nssSawLeadingZero - default: - s = nssSawIntegerDigits - } - - for { - c, err = js.readNextByte() - - if err != nil && !errors.Is(err, io.EOF) { - return nil, err - } - - switch s { - case nssSawLeadingMinus: - switch c { - case '0': - s = nssSawLeadingZero - b.WriteByte(c) - default: - if isDigit(c) { - s = nssSawIntegerDigits - b.WriteByte(c) - } else { - s = nssInvalid - } - } - case nssSawLeadingZero: - switch c { - case '.': - s = nssSawDecimalPoint - b.WriteByte(c) - case 'e', 'E': - s = nssSawExponentLetter - b.WriteByte(c) - case '}', ']', ',': - s = nssDone - default: - if isWhiteSpace(c) || errors.Is(err, io.EOF) { - s = nssDone - } else { - s = nssInvalid - } - } - case nssSawIntegerDigits: - switch c { - case '.': - s = nssSawDecimalPoint - b.WriteByte(c) - case 'e', 'E': - s = nssSawExponentLetter - b.WriteByte(c) - case '}', ']', ',': - s = nssDone - default: - if isWhiteSpace(c) || errors.Is(err, io.EOF) { - s = nssDone - } else if isDigit(c) { - s = nssSawIntegerDigits - b.WriteByte(c) - } else { - s = nssInvalid - } - } - case nssSawDecimalPoint: - t = jttDouble - if isDigit(c) { - s = nssSawFractionDigits - b.WriteByte(c) - } else { - s = nssInvalid - } - case nssSawFractionDigits: - switch c { - case 'e', 'E': - s = nssSawExponentLetter - b.WriteByte(c) - case '}', ']', ',': - s = nssDone - default: - if isWhiteSpace(c) || errors.Is(err, io.EOF) { - s = nssDone - } else if isDigit(c) { - s = nssSawFractionDigits - b.WriteByte(c) - } else { - s = nssInvalid - } - } - case nssSawExponentLetter: - t = jttDouble - switch c { - case '+', '-': - s = nssSawExponentSign - b.WriteByte(c) - default: - if isDigit(c) { - s = nssSawExponentDigits - b.WriteByte(c) - } else { - s = nssInvalid - } - } - case nssSawExponentSign: - if isDigit(c) { - s = nssSawExponentDigits - b.WriteByte(c) - } else { - s = nssInvalid - } - case nssSawExponentDigits: - switch c { - case '}', ']', ',': - s = nssDone - default: - if isWhiteSpace(c) || errors.Is(err, io.EOF) { - s = nssDone - } else if isDigit(c) { - s = nssSawExponentDigits - b.WriteByte(c) - } else { - s = nssInvalid - } - } - } - - switch s { - case nssInvalid: - return nil, fmt.Errorf("invalid JSON number. Position: %d", start) - case nssDone: - js.pos = int(math.Max(0, float64(js.pos-1))) - if t != jttDouble { - v, err := strconv.ParseInt(b.String(), 10, 64) - if err == nil { - if v < math.MinInt32 || v > math.MaxInt32 { - return &jsonToken{t: jttInt64, v: v, p: start}, nil - } - - return &jsonToken{t: jttInt32, v: int32(v), p: start}, nil - } - } - - v, err := strconv.ParseFloat(b.String(), 64) - if err != nil { - return nil, err - } - - return &jsonToken{t: jttDouble, v: v, p: start}, nil - } - } -} |