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()) }