...

Source file src/github.com/godbus/dbus/v5/sig.go

Documentation: github.com/godbus/dbus/v5

     1  package dbus
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  )
     8  
     9  var sigToType = map[byte]reflect.Type{
    10  	'y': byteType,
    11  	'b': boolType,
    12  	'n': int16Type,
    13  	'q': uint16Type,
    14  	'i': int32Type,
    15  	'u': uint32Type,
    16  	'x': int64Type,
    17  	't': uint64Type,
    18  	'd': float64Type,
    19  	's': stringType,
    20  	'g': signatureType,
    21  	'o': objectPathType,
    22  	'v': variantType,
    23  	'h': unixFDIndexType,
    24  }
    25  
    26  // Signature represents a correct type signature as specified by the D-Bus
    27  // specification. The zero value represents the empty signature, "".
    28  type Signature struct {
    29  	str string
    30  }
    31  
    32  // SignatureOf returns the concatenation of all the signatures of the given
    33  // values. It panics if one of them is not representable in D-Bus.
    34  func SignatureOf(vs ...interface{}) Signature {
    35  	var s string
    36  	for _, v := range vs {
    37  		s += getSignature(reflect.TypeOf(v), &depthCounter{})
    38  	}
    39  	return Signature{s}
    40  }
    41  
    42  // SignatureOfType returns the signature of the given type. It panics if the
    43  // type is not representable in D-Bus.
    44  func SignatureOfType(t reflect.Type) Signature {
    45  	return Signature{getSignature(t, &depthCounter{})}
    46  }
    47  
    48  // getSignature returns the signature of the given type and panics on unknown types.
    49  func getSignature(t reflect.Type, depth *depthCounter) (sig string) {
    50  	if !depth.Valid() {
    51  		panic("container nesting too deep")
    52  	}
    53  	defer func() {
    54  		if len(sig) > 255 {
    55  			panic("signature exceeds the length limitation")
    56  		}
    57  	}()
    58  	// handle simple types first
    59  	switch t.Kind() {
    60  	case reflect.Uint8:
    61  		return "y"
    62  	case reflect.Bool:
    63  		return "b"
    64  	case reflect.Int16:
    65  		return "n"
    66  	case reflect.Uint16:
    67  		return "q"
    68  	case reflect.Int, reflect.Int32:
    69  		if t == unixFDType {
    70  			return "h"
    71  		}
    72  		return "i"
    73  	case reflect.Uint, reflect.Uint32:
    74  		if t == unixFDIndexType {
    75  			return "h"
    76  		}
    77  		return "u"
    78  	case reflect.Int64:
    79  		return "x"
    80  	case reflect.Uint64:
    81  		return "t"
    82  	case reflect.Float64:
    83  		return "d"
    84  	case reflect.Ptr:
    85  		return getSignature(t.Elem(), depth)
    86  	case reflect.String:
    87  		if t == objectPathType {
    88  			return "o"
    89  		}
    90  		return "s"
    91  	case reflect.Struct:
    92  		if t == variantType {
    93  			return "v"
    94  		} else if t == signatureType {
    95  			return "g"
    96  		}
    97  		var s string
    98  		for i := 0; i < t.NumField(); i++ {
    99  			field := t.Field(i)
   100  			if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
   101  				s += getSignature(t.Field(i).Type, depth.EnterStruct())
   102  			}
   103  		}
   104  		if len(s) == 0 {
   105  			panic(InvalidTypeError{t})
   106  		}
   107  		return "(" + s + ")"
   108  	case reflect.Array, reflect.Slice:
   109  		return "a" + getSignature(t.Elem(), depth.EnterArray())
   110  	case reflect.Map:
   111  		if !isKeyType(t.Key()) {
   112  			panic(InvalidTypeError{t})
   113  		}
   114  		return "a{" + getSignature(t.Key(), depth.EnterArray().EnterDictEntry()) + getSignature(t.Elem(), depth.EnterArray().EnterDictEntry()) + "}"
   115  	case reflect.Interface:
   116  		return "v"
   117  	}
   118  	panic(InvalidTypeError{t})
   119  }
   120  
   121  // ParseSignature returns the signature represented by this string, or a
   122  // SignatureError if the string is not a valid signature.
   123  func ParseSignature(s string) (sig Signature, err error) {
   124  	if len(s) == 0 {
   125  		return
   126  	}
   127  	if len(s) > 255 {
   128  		return Signature{""}, SignatureError{s, "too long"}
   129  	}
   130  	sig.str = s
   131  	for err == nil && len(s) != 0 {
   132  		err, s = validSingle(s, &depthCounter{})
   133  	}
   134  	if err != nil {
   135  		sig = Signature{""}
   136  	}
   137  
   138  	return
   139  }
   140  
   141  // ParseSignatureMust behaves like ParseSignature, except that it panics if s
   142  // is not valid.
   143  func ParseSignatureMust(s string) Signature {
   144  	sig, err := ParseSignature(s)
   145  	if err != nil {
   146  		panic(err)
   147  	}
   148  	return sig
   149  }
   150  
   151  // Empty returns whether the signature is the empty signature.
   152  func (s Signature) Empty() bool {
   153  	return s.str == ""
   154  }
   155  
   156  // Single returns whether the signature represents a single, complete type.
   157  func (s Signature) Single() bool {
   158  	err, r := validSingle(s.str, &depthCounter{})
   159  	return err != nil && r == ""
   160  }
   161  
   162  // String returns the signature's string representation.
   163  func (s Signature) String() string {
   164  	return s.str
   165  }
   166  
   167  // A SignatureError indicates that a signature passed to a function or received
   168  // on a connection is not a valid signature.
   169  type SignatureError struct {
   170  	Sig    string
   171  	Reason string
   172  }
   173  
   174  func (e SignatureError) Error() string {
   175  	return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
   176  }
   177  
   178  type depthCounter struct {
   179  	arrayDepth, structDepth, dictEntryDepth int
   180  }
   181  
   182  func (cnt *depthCounter) Valid() bool {
   183  	return cnt.arrayDepth <= 32 && cnt.structDepth <= 32 && cnt.dictEntryDepth <= 32
   184  }
   185  
   186  func (cnt depthCounter) EnterArray() *depthCounter {
   187  	cnt.arrayDepth++
   188  	return &cnt
   189  }
   190  
   191  func (cnt depthCounter) EnterStruct() *depthCounter {
   192  	cnt.structDepth++
   193  	return &cnt
   194  }
   195  
   196  func (cnt depthCounter) EnterDictEntry() *depthCounter {
   197  	cnt.dictEntryDepth++
   198  	return &cnt
   199  }
   200  
   201  // Try to read a single type from this string. If it was successful, err is nil
   202  // and rem is the remaining unparsed part. Otherwise, err is a non-nil
   203  // SignatureError and rem is "". depth is the current recursion depth which may
   204  // not be greater than 64 and should be given as 0 on the first call.
   205  func validSingle(s string, depth *depthCounter) (err error, rem string) {
   206  	if s == "" {
   207  		return SignatureError{Sig: s, Reason: "empty signature"}, ""
   208  	}
   209  	if !depth.Valid() {
   210  		return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
   211  	}
   212  	switch s[0] {
   213  	case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
   214  		return nil, s[1:]
   215  	case 'a':
   216  		if len(s) > 1 && s[1] == '{' {
   217  			i := findMatching(s[1:], '{', '}')
   218  			if i == -1 {
   219  				return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
   220  			}
   221  			i++
   222  			rem = s[i+1:]
   223  			s = s[2:i]
   224  			if err, _ = validSingle(s[:1], depth.EnterArray().EnterDictEntry()); err != nil {
   225  				return err, ""
   226  			}
   227  			err, nr := validSingle(s[1:], depth.EnterArray().EnterDictEntry())
   228  			if err != nil {
   229  				return err, ""
   230  			}
   231  			if nr != "" {
   232  				return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
   233  			}
   234  			return nil, rem
   235  		}
   236  		return validSingle(s[1:], depth.EnterArray())
   237  	case '(':
   238  		i := findMatching(s, '(', ')')
   239  		if i == -1 {
   240  			return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
   241  		}
   242  		rem = s[i+1:]
   243  		s = s[1:i]
   244  		for err == nil && s != "" {
   245  			err, s = validSingle(s, depth.EnterStruct())
   246  		}
   247  		if err != nil {
   248  			rem = ""
   249  		}
   250  		return
   251  	}
   252  	return SignatureError{Sig: s, Reason: "invalid type character"}, ""
   253  }
   254  
   255  func findMatching(s string, left, right rune) int {
   256  	n := 0
   257  	for i, v := range s {
   258  		if v == left {
   259  			n++
   260  		} else if v == right {
   261  			n--
   262  		}
   263  		if n == 0 {
   264  			return i
   265  		}
   266  	}
   267  	return -1
   268  }
   269  
   270  // typeFor returns the type of the given signature. It ignores any left over
   271  // characters and panics if s doesn't start with a valid type signature.
   272  func typeFor(s string) (t reflect.Type) {
   273  	err, _ := validSingle(s, &depthCounter{})
   274  	if err != nil {
   275  		panic(err)
   276  	}
   277  
   278  	if t, ok := sigToType[s[0]]; ok {
   279  		return t
   280  	}
   281  	switch s[0] {
   282  	case 'a':
   283  		if s[1] == '{' {
   284  			i := strings.LastIndex(s, "}")
   285  			t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
   286  		} else {
   287  			t = reflect.SliceOf(typeFor(s[1:]))
   288  		}
   289  	case '(':
   290  		t = interfacesType
   291  	}
   292  	return
   293  }
   294  

View as plain text