aboutsummaryrefslogtreecommitdiff
path: root/cpe/v23binding.go
blob: 24fb7b27a4b9dd85c12021a168643ee388971e93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package cpe

import (
  "encoding/json"
  "errors"
  "fmt"
  "strings"
)

// CPE 2.3 binding.
type V23Binding 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).
}

// formatted string prefix
var cpe23Prefix = "cpe:2.3:"

// missing prefix error
var missingPrefix = errors.New("missing CPE 2.3 prefix")

// Create binding from CPE 2.3 formatted string.
func NewV23Binding(s string) (V23Binding, error) {
  // check prefix
  if s[0:len(cpe23Prefix)] != cpe23Prefix {
    return V23Binding{}, missingPrefix
  }

  // tokenize string, check for error
  toks, err := tokenize([]byte(s[len(cpe23Prefix):]))
  if err != nil {
    return V23Binding{}, err
  }

  // check token count
  if len(toks) != 11 {
    err = fmt.Errorf("invalid attribute count: %d != 11", len(toks))
    return V23Binding{}, err
  }

  // create part
  part, err := newPart(toks[0])
  if err != nil {
    return V23Binding{}, 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 V23Binding{}, err
    }
  }

  // build and return result
  return V23Binding {
    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
}

// Serialize CPE 2.3 binding as formatted string.
func (v V23Binding) 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 2.3 binding from JSON string.
func (me *V23Binding) UnmarshalJSON(b []byte) error {
  // decode json string
  var s string
  if err := json.Unmarshal(b, &s); err != nil {
    return err
  }

  // create binding
  binding, err := NewV23Binding(s)
  if err != nil {
    return err
  }

  // save result, return success
  *me = binding
  return nil
}

// Marshal CPE binding as JSON string.
func (v V23Binding) MarshalJSON() ([]byte, error) {
  return json.Marshal(v.String())
}