xref: /aosp_15_r20/external/spdx-tools/rdfloader/parser2v3/utils.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2
3package parser2v3
4
5import (
6	"errors"
7	"fmt"
8	"strings"
9
10	gordfParser "github.com/spdx/gordf/rdfloader/parser"
11	"github.com/spdx/gordf/rdfwriter"
12	urilib "github.com/spdx/gordf/uri"
13	"github.com/spdx/tools-golang/spdx/common"
14)
15
16// a uri is of type baseURI#fragment or baseFragment/subFragment
17// returns fragment or subFragment when given as an input.
18func getLastPartOfURI(uri string) string {
19	if strings.Contains(uri, "#") {
20		parts := strings.Split(uri, "#")
21		return parts[len(parts)-1]
22	}
23	parts := strings.Split(uri, "/")
24	return parts[len(parts)-1]
25}
26
27func isUriValid(uri string) bool {
28	_, err := urilib.NewURIRef(uri)
29	return err == nil
30}
31
32func getNodeTypeFromTriples(triples []*gordfParser.Triple, node *gordfParser.Node) (string, error) {
33	if node == nil {
34		return "", errors.New("empty node passed to find node type")
35	}
36	typeTriples := rdfwriter.FilterTriples(triples, &node.ID, &RDF_TYPE, nil)
37	switch len(typeTriples) {
38	case 0:
39		return "", fmt.Errorf("node{%v} not associated with any type triple", node)
40	case 1:
41		return typeTriples[0].Object.ID, nil
42	default:
43		return "", fmt.Errorf("node{%v} is associated with more than one type triples", node)
44	}
45}
46
47func (parser *rdfParser2_3) nodeToTriples(node *gordfParser.Node) []*gordfParser.Triple {
48	if node == nil {
49		return []*gordfParser.Triple{}
50	}
51	return parser.nodeStringToTriples[node.String()]
52}
53
54// returns which boolean was given as an input
55// string(bool) is the only possible input for which it will not raise any error.
56func boolFromString(boolString string) (bool, error) {
57	switch strings.ToLower(boolString) {
58	case "true":
59		return true, nil
60	case "false":
61		return false, nil
62	default:
63		return false, fmt.Errorf("boolean string can be either true/false")
64	}
65}
66
67/* Function Below this line is taken from the tvloader/parser2v3/utils.go */
68
69// used to extract DocumentRef and SPDXRef values from an SPDX Identifier
70// which can point either to this document or to a different one
71func ExtractDocElementID(value string) (common.DocElementID, error) {
72	docRefID := ""
73	idStr := value
74
75	// check prefix to see if it's a DocumentRef ID
76	if strings.HasPrefix(idStr, "DocumentRef-") {
77		// extract the part that comes between "DocumentRef-" and ":"
78		strs := strings.Split(idStr, ":")
79		// should be exactly two, part before and part after
80		if len(strs) < 2 {
81			return common.DocElementID{}, fmt.Errorf("no colon found although DocumentRef- prefix present")
82		}
83		if len(strs) > 2 {
84			return common.DocElementID{}, fmt.Errorf("more than one colon found")
85		}
86
87		// trim the prefix and confirm non-empty
88		docRefID = strings.TrimPrefix(strs[0], "DocumentRef-")
89		if docRefID == "" {
90			return common.DocElementID{}, fmt.Errorf("document identifier has nothing after prefix")
91		}
92		// and use remainder for element ID parsing
93		idStr = strs[1]
94	}
95
96	// check prefix to confirm it's got the right prefix for element IDs
97	if !strings.HasPrefix(idStr, "SPDXRef-") {
98		return common.DocElementID{}, fmt.Errorf("missing SPDXRef- prefix for element identifier")
99	}
100
101	// make sure no colons are present
102	if strings.Contains(idStr, ":") {
103		// we know this means there was no DocumentRef- prefix, because
104		// we would have handled multiple colons above if it was
105		return common.DocElementID{}, fmt.Errorf("invalid colon in element identifier")
106	}
107
108	// trim the prefix and confirm non-empty
109	eltRefID := strings.TrimPrefix(idStr, "SPDXRef-")
110	if eltRefID == "" {
111		return common.DocElementID{}, fmt.Errorf("element identifier has nothing after prefix")
112	}
113
114	// we're good
115	return common.DocElementID{DocumentRefID: docRefID, ElementRefID: common.ElementID(eltRefID)}, nil
116}
117
118// used to extract SPDXRef values only from an SPDX Identifier which can point
119// to this document only. Use extractDocElementID for parsing IDs that can
120// refer either to this document or a different one.
121func ExtractElementID(value string) (common.ElementID, error) {
122	// check prefix to confirm it's got the right prefix for element IDs
123	if !strings.HasPrefix(value, "SPDXRef-") {
124		return common.ElementID(""), fmt.Errorf("missing SPDXRef- prefix for element identifier")
125	}
126
127	// make sure no colons are present
128	if strings.Contains(value, ":") {
129		return common.ElementID(""), fmt.Errorf("invalid colon in element identifier")
130	}
131
132	// trim the prefix and confirm non-empty
133	eltRefID := strings.TrimPrefix(value, "SPDXRef-")
134	if eltRefID == "" {
135		return common.ElementID(""), fmt.Errorf("element identifier has nothing after prefix")
136	}
137
138	// we're good
139	return common.ElementID(eltRefID), nil
140}
141
142// used to extract key / value from embedded substrings
143// returns subkey, subvalue, nil if no error, or "", "", error otherwise
144func ExtractSubs(value string, sep string) (string, string, error) {
145	// parse the value to see if it's a valid subvalue format
146	sp := strings.SplitN(value, sep, 2)
147	if len(sp) == 1 {
148		return "", "", fmt.Errorf("invalid subvalue format for %s (no %s found)", value, sep)
149	}
150
151	subkey := strings.TrimSpace(sp[0])
152	subvalue := strings.TrimSpace(sp[1])
153
154	return subkey, subvalue, nil
155}
156