github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/smbios/struct_parser.go (about) 1 // Copyright 2016-2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package smbios 6 7 import ( 8 "fmt" 9 "reflect" 10 "strconv" 11 "strings" 12 ) 13 14 type fieldParser interface { 15 ParseField(t *Table, off int) (int, error) 16 } 17 18 var ( 19 fieldTagKey = "smbios" // Tag key for annotations. 20 fieldParserInterfaceType = reflect.TypeOf((*fieldParser)(nil)).Elem() 21 ) 22 23 func parseStruct(t *Table, off int, complete bool, sp interface{}) (int, error) { 24 var err error 25 var ok bool 26 var sv reflect.Value 27 if sv, ok = sp.(reflect.Value); !ok { 28 sv = reflect.Indirect(reflect.ValueOf(sp)) // must be a pointer to struct then, dereference it 29 } 30 svtn := sv.Type().Name() 31 //fmt.Printf("t %s\n", svtn) 32 i := 0 33 for ; i < sv.NumField() && off < t.Len(); i++ { 34 f := sv.Type().Field(i) 35 fv := sv.Field(i) 36 ft := fv.Type() 37 tags := f.Tag.Get(fieldTagKey) 38 //fmt.Printf("XX %02Xh f %s t %s k %s %s\n", off, f.Name, f.Type.Name(), fv.Kind(), tags) 39 // Check tags first 40 ignore := false 41 for _, tag := range strings.Split(tags, ",") { 42 tp := strings.Split(tag, "=") 43 switch tp[0] { 44 case "-": 45 ignore = true 46 case "skip": 47 numBytes, _ := strconv.Atoi(tp[1]) 48 off += numBytes 49 } 50 } 51 if ignore { 52 continue 53 } 54 var verr error 55 switch fv.Kind() { 56 case reflect.Uint8: 57 v, err := t.GetByteAt(off) 58 fv.SetUint(uint64(v)) 59 verr = err 60 off++ 61 case reflect.Uint16: 62 v, err := t.GetWordAt(off) 63 fv.SetUint(uint64(v)) 64 verr = err 65 off += 2 66 case reflect.Uint32: 67 v, err := t.GetDWordAt(off) 68 fv.SetUint(uint64(v)) 69 verr = err 70 off += 4 71 case reflect.Uint64: 72 v, err := t.GetQWordAt(off) 73 fv.SetUint(v) 74 verr = err 75 off += 8 76 case reflect.String: 77 v, _ := t.GetStringAt(off) 78 fv.SetString(v) 79 off++ 80 default: 81 if reflect.PtrTo(ft).Implements(fieldParserInterfaceType) { 82 off, err = fv.Addr().Interface().(fieldParser).ParseField(t, off) 83 if err != nil { 84 return off, err 85 } 86 break 87 } 88 // If it's a struct, just invoke parseStruct recursively. 89 if fv.Kind() == reflect.Struct { 90 off, err = parseStruct(t, off, true /* complete */, fv) 91 if err != nil { 92 return off, err 93 } 94 break 95 } 96 return off, fmt.Errorf("%s.%s: unsupported type %s", svtn, f.Name, fv.Kind()) 97 } 98 if verr != nil { 99 return off, fmt.Errorf("failed to parse %s.%s: %s", svtn, f.Name, verr) 100 } 101 } 102 if complete && i < sv.NumField() { 103 return off, fmt.Errorf("%s incomplete, got %d of %d fields", svtn, i, sv.NumField()) 104 } 105 return off, nil 106 }