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  }