xref: /aosp_15_r20/external/spdx-tools/rdfloader/parser2v3/parse_snippet_info.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2*ba677afaSXin Li
3*ba677afaSXin Lipackage parser2v3
4*ba677afaSXin Li
5*ba677afaSXin Liimport (
6*ba677afaSXin Li	"fmt"
7*ba677afaSXin Li	"strconv"
8*ba677afaSXin Li
9*ba677afaSXin Li	gordfParser "github.com/spdx/gordf/rdfloader/parser"
10*ba677afaSXin Li	"github.com/spdx/gordf/rdfwriter"
11*ba677afaSXin Li	"github.com/spdx/tools-golang/spdx/common"
12*ba677afaSXin Li	"github.com/spdx/tools-golang/spdx/v2_3"
13*ba677afaSXin Li)
14*ba677afaSXin Li
15*ba677afaSXin Li// Snippet Information
16*ba677afaSXin Li// Cardinality: Optional, Many
17*ba677afaSXin Lifunc (parser *rdfParser2_3) getSnippetInformationFromNode2_3(node *gordfParser.Node) (si *v2_3.Snippet, err error) {
18*ba677afaSXin Li	si = &v2_3.Snippet{}
19*ba677afaSXin Li
20*ba677afaSXin Li	err = setSnippetID(node.ID, si)
21*ba677afaSXin Li	if err != nil {
22*ba677afaSXin Li		return nil, err
23*ba677afaSXin Li	}
24*ba677afaSXin Li
25*ba677afaSXin Li	for _, siTriple := range parser.nodeToTriples(node) {
26*ba677afaSXin Li		switch siTriple.Predicate.ID {
27*ba677afaSXin Li		case RDF_TYPE:
28*ba677afaSXin Li			// cardinality: exactly 1
29*ba677afaSXin Li		case SPDX_SNIPPET_FROM_FILE:
30*ba677afaSXin Li			// cardinality: exactly 1
31*ba677afaSXin Li			// file which is associated with the snippet
32*ba677afaSXin Li			_, err := parser.getFileFromNode(siTriple.Object)
33*ba677afaSXin Li			if err != nil {
34*ba677afaSXin Li				return nil, err
35*ba677afaSXin Li			}
36*ba677afaSXin Li			docElemID, err := ExtractDocElementID(getLastPartOfURI(siTriple.Object.ID))
37*ba677afaSXin Li			si.SnippetFromFileSPDXIdentifier = docElemID.ElementRefID
38*ba677afaSXin Li		case SPDX_RANGE:
39*ba677afaSXin Li			// cardinality: min 1
40*ba677afaSXin Li			err = parser.setSnippetRangeFromNode(siTriple.Object, si)
41*ba677afaSXin Li			if err != nil {
42*ba677afaSXin Li				return nil, err
43*ba677afaSXin Li			}
44*ba677afaSXin Li		case SPDX_LICENSE_INFO_IN_SNIPPET:
45*ba677afaSXin Li			// license info in snippet can be NONE, NOASSERTION or SimpleLicensingInfo
46*ba677afaSXin Li			// using AnyLicenseInfo because it can redirect the request and
47*ba677afaSXin Li			// can handle NONE & NOASSERTION
48*ba677afaSXin Li			var anyLicense AnyLicenseInfo
49*ba677afaSXin Li			anyLicense, err = parser.getAnyLicenseFromNode(siTriple.Object)
50*ba677afaSXin Li			if err != nil {
51*ba677afaSXin Li				return nil, fmt.Errorf("error parsing license info in snippet: %v", err)
52*ba677afaSXin Li			}
53*ba677afaSXin Li			si.LicenseInfoInSnippet = append(si.LicenseInfoInSnippet, anyLicense.ToLicenseString())
54*ba677afaSXin Li		case SPDX_NAME:
55*ba677afaSXin Li			si.SnippetName = siTriple.Object.ID
56*ba677afaSXin Li		case SPDX_COPYRIGHT_TEXT:
57*ba677afaSXin Li			si.SnippetCopyrightText = siTriple.Object.ID
58*ba677afaSXin Li		case SPDX_LICENSE_COMMENTS:
59*ba677afaSXin Li			si.SnippetLicenseComments = siTriple.Object.ID
60*ba677afaSXin Li		case RDFS_COMMENT:
61*ba677afaSXin Li			si.SnippetComment = siTriple.Object.ID
62*ba677afaSXin Li		case SPDX_LICENSE_CONCLUDED:
63*ba677afaSXin Li			var anyLicense AnyLicenseInfo
64*ba677afaSXin Li			anyLicense, err = parser.getAnyLicenseFromNode(siTriple.Object)
65*ba677afaSXin Li			if err != nil {
66*ba677afaSXin Li				return nil, fmt.Errorf("error parsing license info in snippet: %v", err)
67*ba677afaSXin Li			}
68*ba677afaSXin Li			si.SnippetLicenseConcluded = anyLicense.ToLicenseString()
69*ba677afaSXin Li		default:
70*ba677afaSXin Li			return nil, fmt.Errorf("unknown predicate %v", siTriple.Predicate.ID)
71*ba677afaSXin Li		}
72*ba677afaSXin Li	}
73*ba677afaSXin Li	return si, nil
74*ba677afaSXin Li}
75*ba677afaSXin Li
76*ba677afaSXin Li// given is the id of the file, sets the snippet to the file in parser.
77*ba677afaSXin Lifunc (parser *rdfParser2_3) setSnippetToFileWithID(snippet *v2_3.Snippet, fileID common.ElementID) error {
78*ba677afaSXin Li	if parser.files[fileID] == nil {
79*ba677afaSXin Li		return fmt.Errorf("snippet refers to an undefined file with ID: %s", fileID)
80*ba677afaSXin Li	}
81*ba677afaSXin Li
82*ba677afaSXin Li	// initializing snippet of the files if it is not defined already
83*ba677afaSXin Li	if parser.files[fileID].Snippets == nil {
84*ba677afaSXin Li		parser.files[fileID].Snippets = map[common.ElementID]*v2_3.Snippet{}
85*ba677afaSXin Li	}
86*ba677afaSXin Li
87*ba677afaSXin Li	// setting the snippet to the file.
88*ba677afaSXin Li	parser.files[fileID].Snippets[snippet.SnippetSPDXIdentifier] = snippet
89*ba677afaSXin Li
90*ba677afaSXin Li	return nil
91*ba677afaSXin Li}
92*ba677afaSXin Li
93*ba677afaSXin Lifunc (parser *rdfParser2_3) setSnippetRangeFromNode(node *gordfParser.Node, si *v2_3.Snippet) error {
94*ba677afaSXin Li	// for a range object, we can have only 3 associated triples:
95*ba677afaSXin Li	//		node -> RDF_TYPE     -> Object
96*ba677afaSXin Li	//      node -> startPointer -> Object
97*ba677afaSXin Li	//      node -> endPointer   -> Object
98*ba677afaSXin Li	associatedTriples := parser.nodeToTriples(node)
99*ba677afaSXin Li	if len(associatedTriples) != 3 {
100*ba677afaSXin Li		return fmt.Errorf("range should be associated with exactly 3 triples, got %d", len(associatedTriples))
101*ba677afaSXin Li	}
102*ba677afaSXin Li
103*ba677afaSXin Li	// Triple 1: Predicate=RDF_TYPE
104*ba677afaSXin Li	typeTriple := rdfwriter.FilterTriples(associatedTriples, &node.ID, &RDF_TYPE, nil)
105*ba677afaSXin Li	if len(typeTriple) != 1 {
106*ba677afaSXin Li		// we had 3 associated triples. out of which 2 is start and end pointer,
107*ba677afaSXin Li		// if we do not have the rdf:type triple as the third one,
108*ba677afaSXin Li		// we have either extra or undefined predicate.
109*ba677afaSXin Li		return fmt.Errorf("every object node must be associated with exactly one rdf:type triple, found: %d", len(typeTriple))
110*ba677afaSXin Li	}
111*ba677afaSXin Li
112*ba677afaSXin Li	// getting start pointer
113*ba677afaSXin Li	startPointerTriples := rdfwriter.FilterTriples(associatedTriples, &node.ID, &PTR_START_POINTER, nil)
114*ba677afaSXin Li	if len(startPointerTriples) != 1 {
115*ba677afaSXin Li		return fmt.Errorf("range object must be associated with exactly 1 startPointer, got %d", len(startPointerTriples))
116*ba677afaSXin Li	}
117*ba677afaSXin Li	startRangeType, start, err := parser.getPointerFromNode(startPointerTriples[0].Object, si)
118*ba677afaSXin Li	if err != nil {
119*ba677afaSXin Li		return fmt.Errorf("error parsing startPointer: %v", err)
120*ba677afaSXin Li	}
121*ba677afaSXin Li
122*ba677afaSXin Li	// getting end pointer
123*ba677afaSXin Li	endPointerTriples := rdfwriter.FilterTriples(associatedTriples, &node.ID, &PTR_END_POINTER, nil)
124*ba677afaSXin Li	if len(startPointerTriples) != 1 {
125*ba677afaSXin Li		return fmt.Errorf("range object must be associated with exactly 1 endPointer, got %d", len(endPointerTriples))
126*ba677afaSXin Li	}
127*ba677afaSXin Li	endRangeType, end, err := parser.getPointerFromNode(endPointerTriples[0].Object, si)
128*ba677afaSXin Li	if err != nil {
129*ba677afaSXin Li		return fmt.Errorf("error parsing endPointer: %v", err)
130*ba677afaSXin Li	}
131*ba677afaSXin Li
132*ba677afaSXin Li	// return error when start and end pointer type is not same.
133*ba677afaSXin Li	if startRangeType != endRangeType {
134*ba677afaSXin Li		return fmt.Errorf("start and end range type doesn't match")
135*ba677afaSXin Li	}
136*ba677afaSXin Li
137*ba677afaSXin Li	si.Ranges = []common.SnippetRange{{
138*ba677afaSXin Li		StartPointer: common.SnippetRangePointer{FileSPDXIdentifier: si.SnippetFromFileSPDXIdentifier},
139*ba677afaSXin Li		EndPointer:   common.SnippetRangePointer{FileSPDXIdentifier: si.SnippetFromFileSPDXIdentifier},
140*ba677afaSXin Li	}}
141*ba677afaSXin Li
142*ba677afaSXin Li	if startRangeType == LINE_RANGE {
143*ba677afaSXin Li		si.Ranges[0].StartPointer.LineNumber = start
144*ba677afaSXin Li		si.Ranges[0].EndPointer.LineNumber = end
145*ba677afaSXin Li	} else {
146*ba677afaSXin Li		si.Ranges[0].StartPointer.Offset = start
147*ba677afaSXin Li		si.Ranges[0].EndPointer.Offset = end
148*ba677afaSXin Li	}
149*ba677afaSXin Li	return nil
150*ba677afaSXin Li}
151*ba677afaSXin Li
152*ba677afaSXin Lifunc (parser *rdfParser2_3) getPointerFromNode(node *gordfParser.Node, si *v2_3.Snippet) (rt RangeType, number int, err error) {
153*ba677afaSXin Li	for _, triple := range parser.nodeToTriples(node) {
154*ba677afaSXin Li		switch triple.Predicate.ID {
155*ba677afaSXin Li		case RDF_TYPE:
156*ba677afaSXin Li		case PTR_REFERENCE:
157*ba677afaSXin Li			err = parser.parseRangeReference(triple.Object, si)
158*ba677afaSXin Li		case PTR_OFFSET:
159*ba677afaSXin Li			number, err = strconv.Atoi(triple.Object.ID)
160*ba677afaSXin Li			rt = BYTE_RANGE
161*ba677afaSXin Li		case PTR_LINE_NUMBER:
162*ba677afaSXin Li			number, err = strconv.Atoi(triple.Object.ID)
163*ba677afaSXin Li			rt = LINE_RANGE
164*ba677afaSXin Li		default:
165*ba677afaSXin Li			err = fmt.Errorf("undefined predicate (%s) for a pointer", triple.Predicate)
166*ba677afaSXin Li		}
167*ba677afaSXin Li		if err != nil {
168*ba677afaSXin Li			return
169*ba677afaSXin Li		}
170*ba677afaSXin Li	}
171*ba677afaSXin Li	if rt == "" {
172*ba677afaSXin Li		err = fmt.Errorf("range type not defined for a pointer")
173*ba677afaSXin Li	}
174*ba677afaSXin Li	return
175*ba677afaSXin Li}
176*ba677afaSXin Li
177*ba677afaSXin Lifunc (parser *rdfParser2_3) parseRangeReference(node *gordfParser.Node, snippet *v2_3.Snippet) error {
178*ba677afaSXin Li	// reference is supposed to be either a resource reference to an already
179*ba677afaSXin Li	// defined or a new file. Unfortunately, I didn't find field where this can be set in the tools-golang data model.
180*ba677afaSXin Li	// todo: set this reference to the snippet
181*ba677afaSXin Li	associatedTriples := rdfwriter.FilterTriples(parser.gordfParserObj.Triples, &node.ID, nil, nil)
182*ba677afaSXin Li	if len(associatedTriples) == 0 {
183*ba677afaSXin Li		return nil
184*ba677afaSXin Li	}
185*ba677afaSXin Li	_, err := parser.getFileFromNode(node)
186*ba677afaSXin Li	if err != nil {
187*ba677afaSXin Li		return fmt.Errorf("error parsing a new file in a reference: %v", err)
188*ba677afaSXin Li	}
189*ba677afaSXin Li	return nil
190*ba677afaSXin Li}
191*ba677afaSXin Li
192*ba677afaSXin Lifunc setSnippetID(uri string, si *v2_3.Snippet) (err error) {
193*ba677afaSXin Li	fragment := getLastPartOfURI(uri)
194*ba677afaSXin Li	si.SnippetSPDXIdentifier, err = ExtractElementID(fragment)
195*ba677afaSXin Li	if err != nil {
196*ba677afaSXin Li		return fmt.Errorf("error setting snippet identifier: %v", uri)
197*ba677afaSXin Li	}
198*ba677afaSXin Li	return nil
199*ba677afaSXin Li}
200