diff options
author | Paul Duncan <pabs@pablotron.org> | 2022-02-02 04:08:55 -0500 |
---|---|---|
committer | Paul Duncan <pabs@pablotron.org> | 2022-02-02 04:08:55 -0500 |
commit | b6496c2d20904e665116133a9e9bf9ae6e3b45b8 (patch) | |
tree | 72ca645269e545e494e1d6d91145134584abc673 /internal/cpe/cpe.go | |
parent | 1b9eb2eddf322560c37efa2ef2eb63d5ab661be8 (diff) | |
download | cvez-b6496c2d20904e665116133a9e9bf9ae6e3b45b8.tar.bz2 cvez-b6496c2d20904e665116133a9e9bf9ae6e3b45b8.zip |
add internal/cpe
Diffstat (limited to 'internal/cpe/cpe.go')
-rw-r--r-- | internal/cpe/cpe.go | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/internal/cpe/cpe.go b/internal/cpe/cpe.go new file mode 100644 index 0000000..73930e8 --- /dev/null +++ b/internal/cpe/cpe.go @@ -0,0 +1,94 @@ +// CPE 2.3 formatted string parser. +// +// Source: NISTIR 7605, figure 6-3: +// https://nvlpubs.nist.gov/nistpubs/Legacy/IR/nistir7695.pdf +package cpe + +import ( + "fmt" +) + +//go:generate stringer -linecomment -type=tokenType + +// token type +type tokenType byte + +const ( + anyToken tokenType = iota // any + naToken // na + valToken // val +) + +// token +type token struct { + Type tokenType // token type + Val string // token value +} + +// parse buffer into token. +func newToken(val []byte) token { + if len(val) > 0 { + switch val[0] { + case '*': + return token { Type: anyToken } + case '-': + return token { Type: naToken } + default: + return token { Type: valToken, Val: string(val) } + } + } else { + // empty value + return token { Type: valToken, Val: "" } + } +} + +// Parse buffer into slice of tokens. +func tokenize(buf []byte) ([]token, error) { + // build result + var r []token + + // current token and escape state + var curr []byte + esc := false + + // build result + for _, b := range(buf) { + if esc { + switch b { + // valid escaped characters + case '\\', '*', '-', '!', '"', '#', '$', '%', '&', '\'', '(', ')', + '+', ',', '/', ':', ';', '<', '=', '>', '@', '[', ']', '^', '`', + '{', '|', '}', '~': + curr = append(curr, b) + esc = false + default: + return r, fmt.Errorf("invalid escape byte: 0x%02x", b) + } + } else { + switch b { + case '\\': + esc = true + case ':': + // push token, clear buffer + r = append(r, newToken(curr)) + curr = nil + case 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '-', '.', '_', '*', '?': + curr = append(curr, b) + default: + return r, fmt.Errorf("invalid byte: 0x%02x", b) + } + } + } + + if len(curr) > 0 { + // push token, clear buffer + r = append(r, newToken(curr)) + curr = nil + } + + // return success + return r, nil +} |