github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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 ptm, _ := reflect.PtrTo(ft).MethodByName("ParseField") 83 rv := ptm.Func.Call([]reflect.Value{fv.Addr(), reflect.ValueOf(t), reflect.ValueOf(off)}) 84 off = int(rv[0].Int()) 85 if !rv[1].IsNil() { 86 err = rv[1].Interface().(error) 87 return off, err 88 } 89 break 90 } 91 // If it's a struct, just invoke parseStruct recursively. 92 if fv.Kind() == reflect.Struct { 93 off, err = parseStruct(t, off, true /* complete */, fv) 94 if err != nil { 95 return off, err 96 } 97 break 98 } 99 return off, fmt.Errorf("%s.%s: unsupported type %s", svtn, f.Name, fv.Kind()) 100 } 101 if verr != nil { 102 return off, fmt.Errorf("failed to parse %s.%s: %s", svtn, f.Name, verr) 103 } 104 } 105 if complete && i < sv.NumField() { 106 return off, fmt.Errorf("%s incomplete, got %d of %d fields", svtn, i, sv.NumField()) 107 } 108 return off, nil 109 }