Skip to content
Snippets Groups Projects
decode.go 35.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    
    			n, err := strconv.ParseUint(string(item), 10, 64)
    
    			if err != nil || v.OverflowUint(n) {
    
    				d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
    
    			v.SetUint(n)
    
    		case reflect.Float32, reflect.Float64:
    
    			n, err := strconv.ParseFloat(string(item), v.Type().Bits())
    
    			if err != nil || v.OverflowFloat(n) {
    
    				d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
    
    			v.SetFloat(n)
    
    // The xxxInterface routines build up a value to be stored
    
    // in an empty interface. They are not strictly necessary,
    
    // but they avoid the weight of reflection in this common case.
    
    
    // valueInterface is like value but returns any.
    
    func (d *decodeState) valueInterface() (val any) {
    
    		panic(phasePanicMsg)
    
    	case scanBeginArray:
    
    		val = d.arrayInterface()
    
    	case scanBeginObject:
    
    		val = d.objectInterface()
    
    	case scanBeginLiteral:
    
    		val = d.literalInterface()
    
    // arrayInterface is like array but returns []any.
    
    func (d *decodeState) arrayInterface() []any {
    	var v = make([]any, 0)
    
    	for {
    		// Look ahead for ] - can only happen on first iteration.
    
    		d.scanWhile(scanSkipSpace)
    		if d.opcode == scanEndArray {
    
    		v = append(v, d.valueInterface())
    
    
    		// Next token must be , or ].
    
    		if d.opcode == scanSkipSpace {
    			d.scanWhile(scanSkipSpace)
    		}
    		if d.opcode == scanEndArray {
    
    		if d.opcode != scanArrayValue {
    
    			panic(phasePanicMsg)
    
    // objectInterface is like object but returns map[string]any.
    
    func (d *decodeState) objectInterface() map[string]any {
    	m := make(map[string]any)
    
    	for {
    		// Read opening " of string key or closing }.
    
    		d.scanWhile(scanSkipSpace)
    		if d.opcode == scanEndObject {
    
    			// closing } - can only happen on first iteration.
    			break
    		}
    
    		if d.opcode != scanBeginLiteral {
    
    			panic(phasePanicMsg)
    
    		item := d.data[start:d.readIndex()]
    
    			panic(phasePanicMsg)
    
    		}
    
    		// Read : before value.
    
    		if d.opcode == scanSkipSpace {
    			d.scanWhile(scanSkipSpace)
    
    		if d.opcode != scanObjectKey {
    
    			panic(phasePanicMsg)
    
    		d.scanWhile(scanSkipSpace)
    
    		m[key] = d.valueInterface()
    
    
    		// Next token must be , or }.
    
    		if d.opcode == scanSkipSpace {
    			d.scanWhile(scanSkipSpace)
    		}
    		if d.opcode == scanEndObject {
    
    		if d.opcode != scanObjectValue {
    
    			panic(phasePanicMsg)
    
    // literalInterface consumes and returns a literal from d.data[d.off-1:] and
    // it reads the following byte ahead. The first byte of the literal has been
    // read already (that's how the caller knows it's a literal).
    
    func (d *decodeState) literalInterface() any {
    
    	// All bytes inside literal return scanContinue op code.
    
    	item := d.data[start:d.readIndex()]
    
    
    	switch c := item[0]; c {
    	case 'n': // null
    
    
    	case 't', 'f': // true, false
    
    
    	case '"': // string
    
    			panic(phasePanicMsg)
    
    
    	default: // number
    		if c != '-' && (c < '0' || c > '9') {
    
    			panic(phasePanicMsg)
    
    		n, err := d.convertNumber(string(item))
    
    		if err != nil {
    
    			d.saveError(err)
    
    	}
    }
    
    // getu4 decodes \uXXXX from the beginning of s, returning the hex value,
    // or it returns -1.
    
    func getu4(s []byte) rune {
    
    	if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
    		return -1
    	}
    
    	var r rune
    	for _, c := range s[2:6] {
    		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)
    
    }
    
    // unquote converts a quoted JSON string literal s into an actual string t.
    // The rules are different than for Go, so cannot use strconv.Unquote.
    
    func unquote(s []byte) (t string, ok bool) {
    	s, ok = unquoteBytes(s)
    
    // unquoteBytes should be an internal detail,
    // but widely used packages access it using linkname.
    // Notable members of the hall of shame include:
    //   - github.com/bytedance/sonic
    //
    // Do not remove or change the type signature.
    // See go.dev/issue/67401.
    //
    //go:linkname unquoteBytes
    
    func unquoteBytes(s []byte) (t []byte, ok bool) {
    	if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
    
    	s = s[1 : len(s)-1]
    
    
    	// Check for unusual characters. If there are none,
    	// then no unquoting is needed, so return a slice of the
    	// original bytes.
    	r := 0
    	for r < len(s) {
    		c := s[r]
    		if c == '\\' || c == '"' || c < ' ' {
    			break
    		}
    		if c < utf8.RuneSelf {
    			r++
    			continue
    		}
    		rr, size := utf8.DecodeRune(s[r:])
    		if rr == utf8.RuneError && size == 1 {
    			break
    		}
    		r += size
    	}
    	if r == len(s) {
    
    	b := make([]byte, len(s)+2*utf8.UTFMax)
    
    	w := copy(b, s[0:r])
    	for r < len(s) {
    
    		// Out of room? Can only happen if s is full of
    
    		// malformed UTF-8 and we're replacing each
    		// byte with RuneError.
    		if w >= len(b)-2*utf8.UTFMax {
    			nb := make([]byte, (len(b)+utf8.UTFMax)*2)
    			copy(nb, b[0:w])
    			b = nb
    		}
    		switch c := s[r]; {
    		case c == '\\':
    			r++
    
    			if r >= len(s) {
    
    				return
    			}
    			switch s[r] {
    			default:
    				return
    			case '"', '\\', '/', '\'':
    				b[w] = s[r]
    				r++
    				w++
    			case 'b':
    				b[w] = '\b'
    				r++
    				w++
    			case 'f':
    				b[w] = '\f'
    				r++
    				w++
    			case 'n':
    				b[w] = '\n'
    				r++
    				w++
    			case 'r':
    				b[w] = '\r'
    				r++
    				w++
    			case 't':
    				b[w] = '\t'
    				r++
    				w++
    			case 'u':
    				r--
    
    				rr := getu4(s[r:])
    				if rr < 0 {
    
    				if utf16.IsSurrogate(rr) {
    					rr1 := getu4(s[r:])
    					if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
    
    						// A valid pair; consume.
    						r += 6
    
    						w += utf8.EncodeRune(b[w:], dec)
    
    						break
    					}
    					// Invalid surrogate; fall back to replacement rune.
    
    					rr = unicode.ReplacementChar
    
    				w += utf8.EncodeRune(b[w:], rr)
    
    			}
    
    		// Quote, control characters are invalid.
    		case c == '"', c < ' ':
    			return
    
    		// ASCII
    		case c < utf8.RuneSelf:
    			b[w] = c
    			r++
    			w++
    
    		// Coerce to well-formed UTF-8.
    		default:
    
    			rr, size := utf8.DecodeRune(s[r:])
    
    			w += utf8.EncodeRune(b[w:], rr)
    
    	return b[0:w], true