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 }
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 }
// 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 }
// 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 }
// 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) } } }