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