Beispiel #1
0
func (b *structBuilder) Elem(i int) Builder {
	if b == nil || i < 0 {
		return nobuilder
	}
	switch v := b.val.(type) {
	case *reflect.ArrayValue:
		if i < v.Len() {
			return &structBuilder{val: v.Elem(i)}
		}
	case *reflect.SliceValue:
		if i >= v.Cap() {
			n := v.Cap()
			if n < 8 {
				n = 8
			}
			for n <= i {
				n *= 2
			}
			nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), v.Len(), n)
			reflect.ArrayCopy(nv, v)
			v.Set(nv)
		}
		if v.Len() <= i && i < v.Cap() {
			v.SetLen(i + 1)
		}
		if i < v.Len() {
			return &structBuilder{val: v.Elem(i)}
		}
	}
	return nobuilder
}
Beispiel #2
0
func (self *structBuilder) Key(k string) Builder {
	if self == nil {
		return nobuilder
	}
	switch v := reflect.Indirect(self.val).(type) {
	case *reflect.StructValue:
		t := v.Type().(*reflect.StructType)
		// Case-insensitive field lookup.
		k = strings.ToLower(k)
		for i := 0; i < t.NumField(); i++ {
			if strings.ToLower(t.Field(i).Name) == k {
				return &structBuilder{val: v.Field(i)}
			}
		}

	case *reflect.MapValue:
		t := v.Type().(*reflect.MapType)
		if t.Key() != reflect.Typeof(k) {
			break
		}
		key := reflect.NewValue(k)
		elem := v.Elem(key)
		if elem == nil {
			v.SetElem(key, reflect.MakeZero(t.Elem()))
			elem = v.Elem(key)
		}
		return &structBuilder{val: elem, map_: v, key: key}

	case *reflect.SliceValue:
		index, err := strconv.Atoi(k)
		if err != nil {
			return nobuilder
		}
		if index < v.Len() {
			return &structBuilder{val: v.Elem(index)}
		}
		if index < v.Cap() {
			v.SetLen(index + 1)
			return &structBuilder{val: v.Elem(index)}
		}
		newCap := v.Cap() * 2
		if index >= newCap {
			newCap = index*2 + 1
		}
		temp := reflect.MakeSlice(v.Type().(*reflect.SliceType), index+1, newCap)
		reflect.ArrayCopy(temp, v)
		v.Set(temp)
		return &structBuilder{val: v.Elem(index)}
	}
	return nobuilder
}
Beispiel #3
0
// Unmarshal a single XML element into val.
func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
	// Find start element if we need it.
	if start == nil {
		for {
			tok, err := p.Token()
			if err != nil {
				return err
			}
			if t, ok := tok.(StartElement); ok {
				start = &t
				break
			}
		}
	}

	if pv, ok := val.(*reflect.PtrValue); ok {
		if pv.Get() == 0 {
			zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
			pv.PointTo(zv)
			val = zv
		} else {
			val = pv.Elem()
		}
	}

	var (
		data        []byte
		saveData    reflect.Value
		comment     []byte
		saveComment reflect.Value
		sv          *reflect.StructValue
		styp        *reflect.StructType
	)
	switch v := val.(type) {
	default:
		return os.ErrorString("unknown type " + v.Type().String())

	case *reflect.BoolValue:
		v.Set(true)

	case *reflect.SliceValue:
		typ := v.Type().(*reflect.SliceType)
		if _, ok := typ.Elem().(*reflect.Uint8Type); ok {
			// []byte
			saveData = v
			break
		}

		// Slice of element values.
		// Grow slice.
		n := v.Len()
		if n >= v.Cap() {
			ncap := 2 * n
			if ncap < 4 {
				ncap = 4
			}
			new := reflect.MakeSlice(typ, n, ncap)
			reflect.ArrayCopy(new, v)
			v.Set(new)
		}
		v.SetLen(n + 1)

		// Recur to read element into slice.
		if err := p.unmarshal(v.Elem(n), start); err != nil {
			v.SetLen(n)
			return err
		}
		return nil

	case *reflect.StringValue,
		*reflect.IntValue, *reflect.UintValue, *reflect.UintptrValue,
		*reflect.Int8Value, *reflect.Int16Value, *reflect.Int32Value, *reflect.Int64Value,
		*reflect.Uint8Value, *reflect.Uint16Value, *reflect.Uint32Value, *reflect.Uint64Value,
		*reflect.FloatValue, *reflect.Float32Value, *reflect.Float64Value:
		saveData = v

	case *reflect.StructValue:
		if _, ok := v.Interface().(Name); ok {
			v.Set(reflect.NewValue(start.Name).(*reflect.StructValue))
			break
		}

		sv = v
		typ := sv.Type().(*reflect.StructType)
		styp = typ
		// Assign name.
		if f, ok := typ.FieldByName("XMLName"); ok {
			// Validate element name.
			if f.Tag != "" {
				tag := f.Tag
				ns := ""
				i := strings.LastIndex(tag, " ")
				if i >= 0 {
					ns, tag = tag[0:i], tag[i+1:]
				}
				if tag != start.Name.Local {
					return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
				}
				if ns != "" && ns != start.Name.Space {
					e := "expected element <" + tag + "> in name space " + ns + " but have "
					if start.Name.Space == "" {
						e += "no name space"
					} else {
						e += start.Name.Space
					}
					return UnmarshalError(e)
				}
			}

			// Save
			v := sv.FieldByIndex(f.Index)
			if _, ok := v.Interface().(Name); !ok {
				return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
			}
			v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue))
		}

		// Assign attributes.
		// Also, determine whether we need to save character data or comments.
		for i, n := 0, typ.NumField(); i < n; i++ {
			f := typ.Field(i)
			switch f.Tag {
			case "attr":
				strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue)
				if !ok {
					return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
				}
				// Look for attribute.
				val := ""
				k := strings.ToLower(f.Name)
				for _, a := range start.Attr {
					if fieldName(a.Name.Local) == k {
						val = a.Value
						break
					}
				}
				strv.Set(val)

			case "comment":
				if saveComment == nil {
					saveComment = sv.FieldByIndex(f.Index)
				}

			case "chardata":
				if saveData == nil {
					saveData = sv.FieldByIndex(f.Index)
				}
			}
		}
	}

	// Find end element.
	// Process sub-elements along the way.
Loop:
	for {
		tok, err := p.Token()
		if err != nil {
			return err
		}
		switch t := tok.(type) {
		case StartElement:
			// Sub-element.
			// Look up by tag name.
			// If that fails, fall back to mop-up field named "Any".
			if sv != nil {
				k := fieldName(t.Name.Local)
				any := -1
				for i, n := 0, styp.NumField(); i < n; i++ {
					f := styp.Field(i)
					if strings.ToLower(f.Name) == k {
						if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
							return err
						}
						continue Loop
					}
					if any < 0 && f.Name == "Any" {
						any = i
					}
				}
				if any >= 0 {
					if err := p.unmarshal(sv.FieldByIndex(styp.Field(any).Index), &t); err != nil {
						return err
					}
					continue Loop
				}
			}
			// Not saving sub-element but still have to skip over it.
			if err := p.Skip(); err != nil {
				return err
			}

		case EndElement:
			break Loop

		case CharData:
			if saveData != nil {
				data = bytes.Add(data, t)
			}

		case Comment:
			if saveComment != nil {
				comment = bytes.Add(comment, t)
			}
		}
	}

	var err os.Error
	// Helper functions for integer and unsigned integer conversions
	var itmp int64
	getInt64 := func() bool {
		itmp, err = strconv.Atoi64(string(data))
		// TODO: should check sizes
		return err == nil
	}
	var utmp uint64
	getUint64 := func() bool {
		utmp, err = strconv.Atoui64(string(data))
		// TODO: check for overflow?
		return err == nil
	}
	var ftmp float64
	getFloat64 := func() bool {
		ftmp, err = strconv.Atof64(string(data))
		// TODO: check for overflow?
		return err == nil
	}

	// Save accumulated data and comments
	switch t := saveData.(type) {
	case nil:
		// Probably a comment, handled below
	default:
		return os.ErrorString("cannot happen: unknown type " + t.Type().String())
	case *reflect.IntValue:
		if !getInt64() {
			return err
		}
		t.Set(int(itmp))
	case *reflect.Int8Value:
		if !getInt64() {
			return err
		}
		t.Set(int8(itmp))
	case *reflect.Int16Value:
		if !getInt64() {
			return err
		}
		t.Set(int16(itmp))
	case *reflect.Int32Value:
		if !getInt64() {
			return err
		}
		t.Set(int32(itmp))
	case *reflect.Int64Value:
		if !getInt64() {
			return err
		}
		t.Set(itmp)
	case *reflect.UintValue:
		if !getUint64() {
			return err
		}
		t.Set(uint(utmp))
	case *reflect.Uint8Value:
		if !getUint64() {
			return err
		}
		t.Set(uint8(utmp))
	case *reflect.Uint16Value:
		if !getUint64() {
			return err
		}
		t.Set(uint16(utmp))
	case *reflect.Uint32Value:
		if !getUint64() {
			return err
		}
		t.Set(uint32(utmp))
	case *reflect.Uint64Value:
		if !getUint64() {
			return err
		}
		t.Set(utmp)
	case *reflect.UintptrValue:
		if !getUint64() {
			return err
		}
		t.Set(uintptr(utmp))
	case *reflect.FloatValue:
		if !getFloat64() {
			return err
		}
		t.Set(float(ftmp))
	case *reflect.Float32Value:
		if !getFloat64() {
			return err
		}
		t.Set(float32(ftmp))
	case *reflect.Float64Value:
		if !getFloat64() {
			return err
		}
		t.Set(ftmp)
	case *reflect.StringValue:
		t.Set(string(data))
	case *reflect.SliceValue:
		t.Set(reflect.NewValue(data).(*reflect.SliceValue))
	}

	switch t := saveComment.(type) {
	case *reflect.StringValue:
		t.Set(string(comment))
	case *reflect.SliceValue:
		t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
	}

	return nil
}
Beispiel #4
0
// parseField is the main parsing function. Given a byte array and an offset
// into the array, it will try to parse a suitable ASN.1 value out and store it
// in the given Value.
func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
	offset = initOffset
	fieldType := v.Type()

	// If we have run out of data, it may be that there are optional elements at the end.
	if offset == len(bytes) {
		if !setDefaultValue(v, params) {
			err = SyntaxError{"sequence truncated"}
		}
		return
	}

	// Deal with raw values.
	if fieldType == rawValueType {
		var t tagAndLength
		t, offset, err = parseTagAndLength(bytes, offset)
		if err != nil {
			return
		}
		if invalidLength(offset, t.length, len(bytes)) {
			err = SyntaxError{"data truncated"}
			return
		}
		result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length]}
		offset += t.length
		v.(*reflect.StructValue).Set(reflect.NewValue(result).(*reflect.StructValue))
		return
	}

	// Deal with the ANY type.
	if ifaceType, ok := fieldType.(*reflect.InterfaceType); ok && ifaceType.NumMethod() == 0 {
		ifaceValue := v.(*reflect.InterfaceValue)
		var t tagAndLength
		t, offset, err = parseTagAndLength(bytes, offset)
		if err != nil {
			return
		}
		if invalidLength(offset, t.length, len(bytes)) {
			err = SyntaxError{"data truncated"}
			return
		}
		var result interface{}
		if !t.isCompound && t.class == classUniversal {
			innerBytes := bytes[offset : offset+t.length]
			switch t.tag {
			case tagPrintableString:
				result, err = parsePrintableString(innerBytes)
			case tagIA5String:
				result, err = parseIA5String(innerBytes)
			case tagInteger:
				result, err = parseInt64(innerBytes)
			case tagBitString:
				result, err = parseBitString(innerBytes)
			case tagOID:
				result, err = parseObjectIdentifier(innerBytes)
			case tagUTCTime:
				result, err = parseUTCTime(innerBytes)
			case tagOctetString:
				result = innerBytes
			default:
				// If we don't know how to handle the type, we just leave Value as nil.
			}
		}
		offset += t.length
		if err != nil {
			return
		}
		if result != nil {
			ifaceValue.Set(reflect.NewValue(result))
		}
		return
	}
	universalTag, compoundType, ok1 := getUniversalType(fieldType)
	if !ok1 {
		err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
		return
	}

	t, offset, err := parseTagAndLength(bytes, offset)
	if err != nil {
		return
	}
	if params.explicit {
		if t.class == classContextSpecific && t.tag == *params.tag && t.isCompound {
			t, offset, err = parseTagAndLength(bytes, offset)
			if err != nil {
				return
			}
		} else {
			// The tags didn't match, it might be an optional element.
			ok := setDefaultValue(v, params)
			if ok {
				offset = initOffset
			} else {
				err = StructuralError{"explicitly tagged member didn't match"}
			}
			return
		}
	}

	// Special case for strings: PrintableString and IA5String both map to
	// the Go type string. getUniversalType returns the tag for
	// PrintableString when it sees a string so, if we see an IA5String on
	// the wire, we change the universal type to match.
	if universalTag == tagPrintableString && t.tag == tagIA5String {
		universalTag = tagIA5String
	}

	expectedClass := classUniversal
	expectedTag := universalTag

	if !params.explicit && params.tag != nil {
		expectedClass = classContextSpecific
		expectedTag = *params.tag
	}

	// We have unwrapped any explicit tagging at this point.
	if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
		// Tags don't match. Again, it could be an optional element.
		ok := setDefaultValue(v, params)
		if ok {
			offset = initOffset
		} else {
			err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s %#v", expectedTag, t, params, fieldType.Name(), bytes[offset:len(bytes)])}
		}
		return
	}
	if invalidLength(offset, t.length, len(bytes)) {
		err = SyntaxError{"data truncated"}
		return
	}
	innerBytes := bytes[offset : offset+t.length]

	// We deal with the structures defined in this package first.
	switch fieldType {
	case objectIdentifierType:
		newSlice, err1 := parseObjectIdentifier(innerBytes)
		sliceValue := v.(*reflect.SliceValue)
		sliceValue.Set(reflect.MakeSlice(sliceValue.Type().(*reflect.SliceType), len(newSlice), len(newSlice)))
		if err1 == nil {
			reflect.ArrayCopy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
		}
		offset += t.length
		err = err1
		return
	case bitStringType:
		structValue := v.(*reflect.StructValue)
		bs, err1 := parseBitString(innerBytes)
		offset += t.length
		if err1 == nil {
			structValue.Set(reflect.NewValue(bs).(*reflect.StructValue))
		}
		err = err1
		return
	case timeType:
		structValue := v.(*reflect.StructValue)
		time, err1 := parseUTCTime(innerBytes)
		offset += t.length
		if err1 == nil {
			structValue.Set(reflect.NewValue(time).(*reflect.StructValue))
		}
		err = err1
		return
	}
	switch val := v.(type) {
	case *reflect.BoolValue:
		parsedBool, err1 := parseBool(innerBytes)
		offset += t.length
		if err1 == nil {
			val.Set(parsedBool)
		}
		err = err1
		return
	case *reflect.IntValue:
		parsedInt, err1 := parseInt(innerBytes)
		offset += t.length
		if err1 == nil {
			val.Set(parsedInt)
		}
		err = err1
		return
	case *reflect.Int64Value:
		parsedInt, err1 := parseInt64(innerBytes)
		offset += t.length
		if err1 == nil {
			val.Set(parsedInt)
		}
		err = err1
		return
	case *reflect.StructValue:
		structType := fieldType.(*reflect.StructType)
		innerOffset := 0
		for i := 0; i < structType.NumField(); i++ {
			field := structType.Field(i)
			innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
			if err != nil {
				return
			}
		}
		offset += t.length
		// We allow extra bytes at the end of the SEQUENCE because
		// adding elements to the end has been used in X.509 as the
		// version numbers have increased.
		return
	case *reflect.SliceValue:
		sliceType := fieldType.(*reflect.SliceType)
		if _, ok := sliceType.Elem().(*reflect.Uint8Type); ok {
			val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
			reflect.ArrayCopy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
			return
		}
		newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
		offset += t.length
		if err1 == nil {
			val.Set(newSlice)
		}
		err = err1
		return
	case *reflect.StringValue:
		var v string
		switch universalTag {
		case tagPrintableString:
			v, err = parsePrintableString(innerBytes)
		case tagIA5String:
			v, err = parseIA5String(innerBytes)
		default:
			err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
		}
		if err == nil {
			val.Set(v)
		}
		return
	}
	err = StructuralError{"unknown Go type"}
	return
}
Beispiel #5
0
// array consumes an array from d.data[d.off-1:], decoding into the value v.
// the first byte of the array ('[') has been read already.
func (d *decodeState) array(v reflect.Value) {
	// Check for unmarshaler.
	unmarshaler, pv := d.indirect(v, false)
	if unmarshaler != nil {
		d.off--
		err := unmarshaler.UnmarshalJSON(d.next())
		if err != nil {
			d.error(err)
		}
		return
	}
	v = pv

	// Decoding into nil interface?  Switch to non-reflect code.
	iv, ok := v.(*reflect.InterfaceValue)
	if ok {
		iv.Set(reflect.NewValue(d.arrayInterface()))
		return
	}

	// Check type of target.
	av, ok := v.(reflect.ArrayOrSliceValue)
	if !ok {
		d.saveError(&UnmarshalTypeError{"array", v.Type()})
	}

	sv, _ := v.(*reflect.SliceValue)

	i := 0
	for {
		// Look ahead for ] - can only happen on first iteration.
		op := d.scanWhile(scanSkipSpace)
		if op == scanEndArray {
			break
		}

		// Back up so d.value can have the byte we just read.
		d.off--
		d.scan.undo(op)

		// Get element of array, growing if necessary.
		if i >= av.Cap() && sv != nil {
			newcap := sv.Cap() + sv.Cap()/2
			if newcap < 4 {
				newcap = 4
			}
			newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
			reflect.ArrayCopy(newv, sv)
			sv.Set(newv)
		}
		if i >= av.Len() && sv != nil {
			// Must be slice; gave up on array during i >= av.Cap().
			sv.SetLen(i + 1)
		}

		// Decode into element.
		if i < av.Len() {
			d.value(av.Elem(i))
		} else {
			// Ran out of fixed array: skip.
			d.value(nil)
		}
		i++

		// Next token must be , or ].
		op = d.scanWhile(scanSkipSpace)
		if op == scanEndArray {
			break
		}
		if op != scanArrayValue {
			d.error(errPhase)
		}
	}
	if i < av.Len() {
		if sv == nil {
			// Array.  Zero the rest.
			z := reflect.MakeZero(av.Type().(*reflect.ArrayType).Elem())
			for ; i < av.Len(); i++ {
				av.Elem(i).SetValue(z)
			}
		} else {
			sv.SetLen(i)
		}
	}
}