// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later package parser2v2 import ( "fmt" "strings" "github.com/spdx/tools-golang/spdx/common" ) // used to extract key / value from embedded substrings // returns subkey, subvalue, nil if no error, or "", "", error otherwise func extractSubs(value string) (string, string, error) { // parse the value to see if it's a valid subvalue format sp := strings.SplitN(value, ":", 2) if len(sp) == 1 { return "", "", fmt.Errorf("invalid subvalue format for %s (no colon found)", value) } subkey := strings.TrimSpace(sp[0]) subvalue := strings.TrimSpace(sp[1]) return subkey, subvalue, nil } // used to extract DocumentRef and SPDXRef values from an SPDX Identifier // which can point either to this document or to a different one func extractDocElementID(value string) (common.DocElementID, error) { docRefID := "" idStr := value // check prefix to see if it's a DocumentRef ID if strings.HasPrefix(idStr, "DocumentRef-") { // extract the part that comes between "DocumentRef-" and ":" strs := strings.Split(idStr, ":") // should be exactly two, part before and part after if len(strs) < 2 { return common.DocElementID{}, fmt.Errorf("no colon found although DocumentRef- prefix present") } if len(strs) > 2 { return common.DocElementID{}, fmt.Errorf("more than one colon found") } // trim the prefix and confirm non-empty docRefID = strings.TrimPrefix(strs[0], "DocumentRef-") if docRefID == "" { return common.DocElementID{}, fmt.Errorf("document identifier has nothing after prefix") } // and use remainder for element ID parsing idStr = strs[1] } // check prefix to confirm it's got the right prefix for element IDs if !strings.HasPrefix(idStr, "SPDXRef-") { return common.DocElementID{}, fmt.Errorf("missing SPDXRef- prefix for element identifier") } // make sure no colons are present if strings.Contains(idStr, ":") { // we know this means there was no DocumentRef- prefix, because // we would have handled multiple colons above if it was return common.DocElementID{}, fmt.Errorf("invalid colon in element identifier") } // trim the prefix and confirm non-empty eltRefID := strings.TrimPrefix(idStr, "SPDXRef-") if eltRefID == "" { return common.DocElementID{}, fmt.Errorf("element identifier has nothing after prefix") } // we're good return common.DocElementID{DocumentRefID: docRefID, ElementRefID: common.ElementID(eltRefID)}, nil } // used to extract SPDXRef values from an SPDX Identifier, OR "special" strings // from a specified set of permitted values. The primary use case for this is // the right-hand side of Relationships, where beginning in SPDX 2.2 the values // "NONE" and "NOASSERTION" are permitted. If the value does not match one of // the specified permitted values, it will fall back to the ordinary // DocElementID extractor. func extractDocElementSpecial(value string, permittedSpecial []string) (common.DocElementID, error) { // check value against special set first for _, sp := range permittedSpecial { if sp == value { return common.DocElementID{SpecialID: sp}, nil } } // not found, fall back to regular search return extractDocElementID(value) } // used to extract SPDXRef values only from an SPDX Identifier which can point // to this document only. Use extractDocElementID for parsing IDs that can // refer either to this document or a different one. func extractElementID(value string) (common.ElementID, error) { // check prefix to confirm it's got the right prefix for element IDs if !strings.HasPrefix(value, "SPDXRef-") { return common.ElementID(""), fmt.Errorf("missing SPDXRef- prefix for element identifier") } // make sure no colons are present if strings.Contains(value, ":") { return common.ElementID(""), fmt.Errorf("invalid colon in element identifier") } // trim the prefix and confirm non-empty eltRefID := strings.TrimPrefix(value, "SPDXRef-") if eltRefID == "" { return common.ElementID(""), fmt.Errorf("element identifier has nothing after prefix") } // we're good return common.ElementID(eltRefID), nil }