xref: /aosp_15_r20/external/spdx-tools/tvloader/parser2v2/util.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2*ba677afaSXin Li
3*ba677afaSXin Lipackage parser2v2
4*ba677afaSXin Li
5*ba677afaSXin Liimport (
6*ba677afaSXin Li	"fmt"
7*ba677afaSXin Li	"strings"
8*ba677afaSXin Li
9*ba677afaSXin Li	"github.com/spdx/tools-golang/spdx/common"
10*ba677afaSXin Li)
11*ba677afaSXin Li
12*ba677afaSXin Li// used to extract key / value from embedded substrings
13*ba677afaSXin Li// returns subkey, subvalue, nil if no error, or "", "", error otherwise
14*ba677afaSXin Lifunc extractSubs(value string) (string, string, error) {
15*ba677afaSXin Li	// parse the value to see if it's a valid subvalue format
16*ba677afaSXin Li	sp := strings.SplitN(value, ":", 2)
17*ba677afaSXin Li	if len(sp) == 1 {
18*ba677afaSXin Li		return "", "", fmt.Errorf("invalid subvalue format for %s (no colon found)", value)
19*ba677afaSXin Li	}
20*ba677afaSXin Li
21*ba677afaSXin Li	subkey := strings.TrimSpace(sp[0])
22*ba677afaSXin Li	subvalue := strings.TrimSpace(sp[1])
23*ba677afaSXin Li
24*ba677afaSXin Li	return subkey, subvalue, nil
25*ba677afaSXin Li}
26*ba677afaSXin Li
27*ba677afaSXin Li// used to extract DocumentRef and SPDXRef values from an SPDX Identifier
28*ba677afaSXin Li// which can point either to this document or to a different one
29*ba677afaSXin Lifunc extractDocElementID(value string) (common.DocElementID, error) {
30*ba677afaSXin Li	docRefID := ""
31*ba677afaSXin Li	idStr := value
32*ba677afaSXin Li
33*ba677afaSXin Li	// check prefix to see if it's a DocumentRef ID
34*ba677afaSXin Li	if strings.HasPrefix(idStr, "DocumentRef-") {
35*ba677afaSXin Li		// extract the part that comes between "DocumentRef-" and ":"
36*ba677afaSXin Li		strs := strings.Split(idStr, ":")
37*ba677afaSXin Li		// should be exactly two, part before and part after
38*ba677afaSXin Li		if len(strs) < 2 {
39*ba677afaSXin Li			return common.DocElementID{}, fmt.Errorf("no colon found although DocumentRef- prefix present")
40*ba677afaSXin Li		}
41*ba677afaSXin Li		if len(strs) > 2 {
42*ba677afaSXin Li			return common.DocElementID{}, fmt.Errorf("more than one colon found")
43*ba677afaSXin Li		}
44*ba677afaSXin Li
45*ba677afaSXin Li		// trim the prefix and confirm non-empty
46*ba677afaSXin Li		docRefID = strings.TrimPrefix(strs[0], "DocumentRef-")
47*ba677afaSXin Li		if docRefID == "" {
48*ba677afaSXin Li			return common.DocElementID{}, fmt.Errorf("document identifier has nothing after prefix")
49*ba677afaSXin Li		}
50*ba677afaSXin Li		// and use remainder for element ID parsing
51*ba677afaSXin Li		idStr = strs[1]
52*ba677afaSXin Li	}
53*ba677afaSXin Li
54*ba677afaSXin Li	// check prefix to confirm it's got the right prefix for element IDs
55*ba677afaSXin Li	if !strings.HasPrefix(idStr, "SPDXRef-") {
56*ba677afaSXin Li		return common.DocElementID{}, fmt.Errorf("missing SPDXRef- prefix for element identifier")
57*ba677afaSXin Li	}
58*ba677afaSXin Li
59*ba677afaSXin Li	// make sure no colons are present
60*ba677afaSXin Li	if strings.Contains(idStr, ":") {
61*ba677afaSXin Li		// we know this means there was no DocumentRef- prefix, because
62*ba677afaSXin Li		// we would have handled multiple colons above if it was
63*ba677afaSXin Li		return common.DocElementID{}, fmt.Errorf("invalid colon in element identifier")
64*ba677afaSXin Li	}
65*ba677afaSXin Li
66*ba677afaSXin Li	// trim the prefix and confirm non-empty
67*ba677afaSXin Li	eltRefID := strings.TrimPrefix(idStr, "SPDXRef-")
68*ba677afaSXin Li	if eltRefID == "" {
69*ba677afaSXin Li		return common.DocElementID{}, fmt.Errorf("element identifier has nothing after prefix")
70*ba677afaSXin Li	}
71*ba677afaSXin Li
72*ba677afaSXin Li	// we're good
73*ba677afaSXin Li	return common.DocElementID{DocumentRefID: docRefID, ElementRefID: common.ElementID(eltRefID)}, nil
74*ba677afaSXin Li}
75*ba677afaSXin Li
76*ba677afaSXin Li// used to extract SPDXRef values from an SPDX Identifier, OR "special" strings
77*ba677afaSXin Li// from a specified set of permitted values. The primary use case for this is
78*ba677afaSXin Li// the right-hand side of Relationships, where beginning in SPDX 2.2 the values
79*ba677afaSXin Li// "NONE" and "NOASSERTION" are permitted. If the value does not match one of
80*ba677afaSXin Li// the specified permitted values, it will fall back to the ordinary
81*ba677afaSXin Li// DocElementID extractor.
82*ba677afaSXin Lifunc extractDocElementSpecial(value string, permittedSpecial []string) (common.DocElementID, error) {
83*ba677afaSXin Li	// check value against special set first
84*ba677afaSXin Li	for _, sp := range permittedSpecial {
85*ba677afaSXin Li		if sp == value {
86*ba677afaSXin Li			return common.DocElementID{SpecialID: sp}, nil
87*ba677afaSXin Li		}
88*ba677afaSXin Li	}
89*ba677afaSXin Li	// not found, fall back to regular search
90*ba677afaSXin Li	return extractDocElementID(value)
91*ba677afaSXin Li}
92*ba677afaSXin Li
93*ba677afaSXin Li// used to extract SPDXRef values only from an SPDX Identifier which can point
94*ba677afaSXin Li// to this document only. Use extractDocElementID for parsing IDs that can
95*ba677afaSXin Li// refer either to this document or a different one.
96*ba677afaSXin Lifunc extractElementID(value string) (common.ElementID, error) {
97*ba677afaSXin Li	// check prefix to confirm it's got the right prefix for element IDs
98*ba677afaSXin Li	if !strings.HasPrefix(value, "SPDXRef-") {
99*ba677afaSXin Li		return common.ElementID(""), fmt.Errorf("missing SPDXRef- prefix for element identifier")
100*ba677afaSXin Li	}
101*ba677afaSXin Li
102*ba677afaSXin Li	// make sure no colons are present
103*ba677afaSXin Li	if strings.Contains(value, ":") {
104*ba677afaSXin Li		return common.ElementID(""), fmt.Errorf("invalid colon in element identifier")
105*ba677afaSXin Li	}
106*ba677afaSXin Li
107*ba677afaSXin Li	// trim the prefix and confirm non-empty
108*ba677afaSXin Li	eltRefID := strings.TrimPrefix(value, "SPDXRef-")
109*ba677afaSXin Li	if eltRefID == "" {
110*ba677afaSXin Li		return common.ElementID(""), fmt.Errorf("element identifier has nothing after prefix")
111*ba677afaSXin Li	}
112*ba677afaSXin Li
113*ba677afaSXin Li	// we're good
114*ba677afaSXin Li	return common.ElementID(eltRefID), nil
115*ba677afaSXin Li}
116