diff options
Diffstat (limited to 'internal/cpe/binding.go')
| -rw-r--r-- | internal/cpe/binding.go | 118 | 
1 files changed, 118 insertions, 0 deletions
| diff --git a/internal/cpe/binding.go b/internal/cpe/binding.go new file mode 100644 index 0000000..8c51d7d --- /dev/null +++ b/internal/cpe/binding.go @@ -0,0 +1,118 @@ +package cpe + +import ( +  "encoding/json" +  "errors" +  "fmt" +  "strings" +) + +// Common Platform Enumeration binding. +type Binding struct { +  Part      Part      // Part attribute (NISTIR7695 5.3.3.1). +  Vendor    AvString  // Vendor attribute (NISTIR7695 5.3.3.2). +  Product   AvString  // Product attribute (NISTIR7695 5.3.3.3). +  Version   AvString  // Version attribute (NISTIR7695 5.3.3.4). +  Update    AvString  // Update attribute (NISTIR7695 5.3.3.5). +  Edition   AvString  // Edition attribute (NISTIR7695 5.3.3.6). +  SwEdition AvString  // Software edition attribute (NISTIR7695 5.3.3.7). +  TargetSw  AvString  // Target software attribute (NISTIR7695 5.3.3.8). +  TargetHw  AvString  // Target hardware attribute (NISTIR7695 5.3.3.9). +  Lang      AvString  // Language attribute (NISTIR7695 5.3.3.10). +  Other     AvString  // Other attribute (NISTIR7695 5.3.3.11). +} + +// cpe 2.3 formatted string prefix +var cpe23Prefix = "cpe:2.3:" + +// missing prefix error +var missingPrefix = errors.New("missing CPE 2.3 prefix") + +// Create CPE 2.3 binding from formatted string. +func NewBinding(s string) (Binding, error) { +  // check prefix +  if s[0:len(cpe23Prefix)] != cpe23Prefix { +    return Binding{}, missingPrefix +  } + +  // tokenize string, check for error +  toks, err := tokenize([]byte(s[len(cpe23Prefix):])) +  if err != nil { +    return Binding{}, err +  } + +  // check token count +  if len(toks) != 11 { +    err = fmt.Errorf("invalid attribute count: %d != 11", len(toks)) +    return Binding{}, err +  } + +  // create part +  part, err := newPart(toks[0]) +  if err != nil { +    return Binding{}, err +  } + +  // parse tokens into strings +  strs := make([]AvString, len(toks) - 1) +  for i, t := range(toks[1:]) { +    if strs[i], err = newAvString(t); err != nil { +      return Binding{}, err +    } +  } + +  // build and return result +  return Binding { +    Part: part, +    Vendor: strs[0], +    Product: strs[1], +    Version: strs[2], +    Update: strs[3], +    Edition: strs[4], +    Lang: strs[5], +    SwEdition: strs[6], +    TargetSw: strs[7], +    TargetHw: strs[8], +    Other: strs[9], +  }, nil +} + +func (v Binding) String() string { +  return cpe23Prefix + strings.Join([]string { +    v.Part.String(), +    v.Vendor.String(), +    v.Product.String(), +    v.Version.String(), +    v.Update.String(), +    v.Edition.String(), +    v.Lang.String(), +    v.SwEdition.String(), +    v.TargetSw.String(), +    v.TargetHw.String(), +    v.Other.String(), +  }, ":") +} + +// Unmarshal CPE formatted string from JSON string. +func (me *Binding) UnmarshalJSON(b []byte) error { +  // decode json string +  var s string +  if err := json.Unmarshal(b, &s); err != nil { +    return err +  } + +  // create binding +  binding, err := NewBinding(s) +  if err != nil { +    return err +  } + +  // save result, return success +  *me = binding +  return nil +} + +// Marshal CPE formatted string as JSON string. +func (v Binding) MarshalJSON() ([]byte, error) { +  return json.Marshal(v.String()) +} | 
