package json import ( "errors" "strconv" "unsafe" ) func parseValue(data []byte, pos int, typ *_rawType, ptr unsafe.Pointer) (int, error) { pos = skipWS(data, pos) if pos >= len(data) { return pos, errors.New("json: unexpected end of input") } // Check Unmarshaler interface. iface := ptrToIface(typ, ptr) if iface != nil { if u, ok := iface.(Unmarshaler); ok { start := pos end := skipJSONValue(data, pos) if end < 0 { return pos, errors.New("json: invalid value") } err := u.UnmarshalJSON(data[start:end]) return end, err } } c := data[pos] // null -> zero the field if c == 'n' && pos+4 <= len(data) && string(data[pos:pos+4]) == "null" { zeroField(typ, ptr) return pos + 4, nil } switch typ.kind() { case jkBool: return parseBool(data, pos, ptr) case jkInt, jkInt8, jkInt16, jkInt32, jkInt64: return parseIntField(data, pos, typ, ptr) case jkUint, jkUint8, jkUint16, jkUint32, jkUint64: return parseUintField(data, pos, typ, ptr) case jkFloat32, jkFloat64: return parseFloatField(data, pos, typ, ptr) case jkBytes: return parseStringField(data, pos, ptr) case jkPointer: return parsePtrField(data, pos, typ, ptr) case jkStruct: return parseStructField(data, pos, typ, ptr) case jkSlice: return parseSliceField(data, pos, typ, ptr) case jkMap: return pos, errors.New("json: map types not supported") case jkInterface: return pos, errors.New("json: interface{} fields not supported") } return pos, errors.New("json: unsupported type") } func parseBool(data []byte, pos int, ptr unsafe.Pointer) (int, error) { if pos+4 <= len(data) && string(data[pos:pos+4]) == "true" { *(*bool)(ptr) = true return pos + 4, nil } if pos+5 <= len(data) && string(data[pos:pos+5]) == "false" { *(*bool)(ptr) = false return pos + 5, nil } return pos, errors.New("json: expected boolean") } func parseIntField(data []byte, pos int, typ *_rawType, ptr unsafe.Pointer) (int, error) { if pos >= len(data) || (data[pos] != '-' && (data[pos] < '0' || data[pos] > '9')) { return pos, errors.New("json: expected number for integer field") } start := pos if data[pos] == '-' { pos++ } for pos < len(data) && data[pos] >= '0' && data[pos] <= '9' { pos++ } // Reject floats in integer fields. if pos < len(data) && (data[pos] == '.' || data[pos] == 'e' || data[pos] == 'E') { return start, errors.New("json: cannot unmarshal float into integer field") } n, err := strconv.ParseInt(string(data[start:pos]), 10, 64) if err != nil { return start, errors.New("json: " | err.Error()) } switch typ.size() { case 1: if n < -128 || n > 127 { return start, errors.New("json: integer overflow for int8") } *(*int8)(ptr) = int8(n) case 2: if n < -32768 || n > 32767 { return start, errors.New("json: integer overflow for int16") } *(*int16)(ptr) = int16(n) case 4: if n < -2147483648 || n > 2147483647 { return start, errors.New("json: integer overflow for int32") } *(*int32)(ptr) = int32(n) default: *(*int64)(ptr) = n } return pos, nil } func parseUintField(data []byte, pos int, typ *_rawType, ptr unsafe.Pointer) (int, error) { if pos >= len(data) || data[pos] < '0' || data[pos] > '9' { return pos, errors.New("json: expected number for unsigned integer field") } start := pos for pos < len(data) && data[pos] >= '0' && data[pos] <= '9' { pos++ } if pos < len(data) && (data[pos] == '.' || data[pos] == 'e' || data[pos] == 'E') { return start, errors.New("json: cannot unmarshal float into unsigned integer field") } n, err := strconv.ParseUint(string(data[start:pos]), 10, 64) if err != nil { return start, errors.New("json: " | err.Error()) } switch typ.size() { case 1: if n > 255 { return start, errors.New("json: integer overflow for uint8") } *(*uint8)(ptr) = uint8(n) case 2: if n > 65535 { return start, errors.New("json: integer overflow for uint16") } *(*uint16)(ptr) = uint16(n) case 4: if n > 4294967295 { return start, errors.New("json: integer overflow for uint32") } *(*uint32)(ptr) = uint32(n) default: *(*uint64)(ptr) = n } return pos, nil } func parseFloatField(data []byte, pos int, typ *_rawType, ptr unsafe.Pointer) (int, error) { if pos >= len(data) { return pos, errors.New("json: expected number") } start := pos if data[pos] == '-' { pos++ } for pos < len(data) && data[pos] >= '0' && data[pos] <= '9' { pos++ } if pos < len(data) && data[pos] == '.' { pos++ for pos < len(data) && data[pos] >= '0' && data[pos] <= '9' { pos++ } } if pos < len(data) && (data[pos] == 'e' || data[pos] == 'E') { pos++ if pos < len(data) && (data[pos] == '+' || data[pos] == '-') { pos++ } for pos < len(data) && data[pos] >= '0' && data[pos] <= '9' { pos++ } } f, err := strconv.ParseFloat(string(data[start:pos]), 64) if err != nil { return start, errors.New("json: " | err.Error()) } if typ.size() == 4 { *(*float32)(ptr) = float32(f) } else { *(*float64)(ptr) = f } return pos, nil } func parseStringField(data []byte, pos int, ptr unsafe.Pointer) (int, error) { if pos >= len(data) || data[pos] != '"' { return pos, errors.New("json: expected string") } s, end := scanString(data, pos) if end < 0 { return pos, errors.New("json: unterminated string") } *(*[]byte)(ptr) = []byte(s) return end, nil } func parsePtrField(data []byte, pos int, typ *_rawType, ptr unsafe.Pointer) (int, error) { pos = skipWS(data, pos) if pos+4 <= len(data) && string(data[pos:pos+4]) == "null" { *(*unsafe.Pointer)(ptr) = nil return pos + 4, nil } elemType := typ.elem() elemPtr := *(*unsafe.Pointer)(ptr) if elemPtr == nil { // Allocate new element. buf := []byte{:int(elemType.size())} elemPtr = unsafe.Pointer(&buf[0]) *(*unsafe.Pointer)(ptr) = elemPtr } return parseValue(data, pos, elemType, elemPtr) } func parseStructField(data []byte, pos int, typ *_rawType, ptr unsafe.Pointer) (int, error) { pos = skipWS(data, pos) if pos >= len(data) || data[pos] != '{' { return pos, errors.New("json: expected object") } pos++ sf := structFieldsFor(typ) for { pos = skipWS(data, pos) if pos >= len(data) { return pos, errors.New("json: unexpected end of object") } if data[pos] == '}' { return pos + 1, nil } if data[pos] == ',' { pos++ continue } // Parse key. if data[pos] != '"' { return pos, errors.New("json: expected string key") } key, keyEnd := scanString(data, pos) if keyEnd < 0 { return pos, errors.New("json: unterminated key string") } pos = skipWS(data, keyEnd) if pos >= len(data) || data[pos] != ':' { return pos, errors.New("json: expected colon") } pos = skipWS(data, pos+1) // Look up field. idx, ok := sf.byName[string(key)] if !ok { // Unknown field - skip value. end := skipJSONValue(data, pos) if end < 0 { return pos, errors.New("json: invalid value") } pos = end continue } ft := typ.fieldType(idx) fp := unsafe.Add(ptr, typ.fieldOffset(idx)) var err error pos, err = parseValue(data, pos, ft, fp) if err != nil { return pos, err } } } func parseSliceField(data []byte, pos int, typ *_rawType, ptr unsafe.Pointer) (int, error) { pos = skipWS(data, pos) if pos >= len(data) { return pos, errors.New("json: expected array") } // null -> nil slice if data[pos] == 'n' && pos+4 <= len(data) && string(data[pos:pos+4]) == "null" { *(*_sliceHeader)(ptr) = _sliceHeader{} return pos + 4, nil } if data[pos] != '[' { return pos, errors.New("json: expected array") } pos++ elemType := typ.elem() hdr := (*_sliceHeader)(ptr) // Initialize as empty-but-allocated via makeSliceOf (GC-visible). sp := makeSliceOf(elemType, 0, 4) *hdr = *(*_sliceHeader)(sp) for { pos = skipWS(data, pos) if pos >= len(data) { return pos, errors.New("json: unexpected end of array") } if data[pos] == ']' { return pos + 1, nil } if data[pos] == ',' { pos++ continue } // Grow slice. sliceAppend(ptr, elemType) elemPtr := unsafe.Add(hdr.data, elemType.size()*uintptr(hdr.len-1)) var err error pos, err = parseValue(data, pos, elemType, elemPtr) if err != nil { return pos, err } } } // --- JSON scanner helpers --- func scanString(data []byte, pos int) (string, int) { if pos >= len(data) || data[pos] != '"' { return "", -1 } pos++ start := pos result := []byte{:0:64} for pos < len(data) { if data[pos] == '\\' { result = append(result, data[start:pos]...) pos++ if pos >= len(data) { return "", -1 } switch data[pos] { case '"', '\\', '/': result = append(result, data[pos]) case 'n': result = append(result, '\n') case 'r': result = append(result, '\r') case 't': result = append(result, '\t') case 'b': result = append(result, '\b') case 'f': result = append(result, '\f') case 'u': if pos+4 >= len(data) { return "", -1 } cp := hexVal(data[pos+1])<<12 | hexVal(data[pos+2])<<8 | hexVal(data[pos+3])<<4 | hexVal(data[pos+4]) if cp >= 0xD800 && cp <= 0xDBFF && pos+10 < len(data) && data[pos+5] == '\\' && data[pos+6] == 'u' { lo := hexVal(data[pos+7])<<12 | hexVal(data[pos+8])<<8 | hexVal(data[pos+9])<<4 | hexVal(data[pos+10]) if lo >= 0xDC00 && lo <= 0xDFFF { cp = 0x10000 + (cp-0xD800)*0x400 + (lo - 0xDC00) pos += 6 } } result = appendRune(result, rune(cp)) pos += 4 default: result = append(result, data[pos]) } pos++ start = pos continue } if data[pos] == '"' { result = append(result, data[start:pos]...) return string(result), pos + 1 } pos++ } return "", -1 } func hexVal(c byte) int { if c >= '0' && c <= '9' { return int(c - '0') } if c >= 'a' && c <= 'f' { return int(c-'a') + 10 } if c >= 'A' && c <= 'F' { return int(c-'A') + 10 } return 0 } func appendRune(buf []byte, r rune) []byte { if r < 0x80 { return append(buf, byte(r)) } if r < 0x800 { return append(buf, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F))) } if r < 0x10000 { return append(buf, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F))) } return append(buf, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F))) } func skipWS(data []byte, pos int) int { for pos < len(data) && (data[pos] == ' ' || data[pos] == '\t' || data[pos] == '\n' || data[pos] == '\r') { pos++ } return pos } func skipJSONValue(data []byte, pos int) int { pos = skipWS(data, pos) if pos >= len(data) { return -1 } switch data[pos] { case '"': _, end := scanString(data, pos) return end case '{': return skipBracketed(data, pos, '{', '}') case '[': return skipBracketed(data, pos, '[', ']') case 't': if pos+4 <= len(data) { return pos + 4 } return -1 case 'f': if pos+5 <= len(data) { return pos + 5 } return -1 case 'n': if pos+4 <= len(data) { return pos + 4 } return -1 default: // Number. for pos < len(data) && data[pos] != ',' && data[pos] != '}' && data[pos] != ']' && data[pos] != ' ' && data[pos] != '\t' && data[pos] != '\n' && data[pos] != '\r' { pos++ } return pos } } func skipBracketed(data []byte, pos int, open, close byte) int { if pos >= len(data) || data[pos] != open { return -1 } depth := 1 pos++ inStr := false for pos < len(data) && depth > 0 { if inStr { if data[pos] == '\\' { pos++ } else if data[pos] == '"' { inStr = false } } else { if data[pos] == '"' { inStr = true } else if data[pos] == open { depth++ } else if data[pos] == close { depth-- } } pos++ } if depth != 0 { return -1 } return pos } func zeroField(typ *_rawType, ptr unsafe.Pointer) { sz := typ.size() for i := uintptr(0); i < sz; i++ { *(*byte)(unsafe.Add(ptr, i)) = 0 } }