aboutsummaryrefslogtreecommitdiff
path: root/rdfloader/parser2v3/parse_snippet_info.go
diff options
context:
space:
mode:
authorKeith Zantow <kzantow@gmail.com>2022-10-10 12:36:03 -0400
committerKeith Zantow <kzantow@gmail.com>2022-10-10 12:36:03 -0400
commit0b2bd4be354bdd719c14a720af0ee2140b676dcb (patch)
tree89ea73f357d872d36baa447f55a99ca659a70e9d /rdfloader/parser2v3/parse_snippet_info.go
parentab3e717feaf76784e3939592d98d788d19a4c022 (diff)
downloadspdx-tools-0b2bd4be354bdd719c14a720af0ee2140b676dcb.tar.gz
chore: support for 2.3 features to rdfloader
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Diffstat (limited to 'rdfloader/parser2v3/parse_snippet_info.go')
-rw-r--r--rdfloader/parser2v3/parse_snippet_info.go199
1 files changed, 199 insertions, 0 deletions
diff --git a/rdfloader/parser2v3/parse_snippet_info.go b/rdfloader/parser2v3/parse_snippet_info.go
new file mode 100644
index 0000000..90da873
--- /dev/null
+++ b/rdfloader/parser2v3/parse_snippet_info.go
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+package parser2v3
+
+import (
+ "fmt"
+ "strconv"
+
+ gordfParser "github.com/spdx/gordf/rdfloader/parser"
+ "github.com/spdx/gordf/rdfwriter"
+ "github.com/spdx/tools-golang/spdx/common"
+ "github.com/spdx/tools-golang/spdx/v2_3"
+)
+
+// Snippet Information
+// Cardinality: Optional, Many
+func (parser *rdfParser2_3) getSnippetInformationFromNode2_3(node *gordfParser.Node) (si *v2_3.Snippet, err error) {
+ si = &v2_3.Snippet{}
+
+ err = setSnippetID(node.ID, si)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, siTriple := range parser.nodeToTriples(node) {
+ switch siTriple.Predicate.ID {
+ case RDF_TYPE:
+ // cardinality: exactly 1
+ case SPDX_SNIPPET_FROM_FILE:
+ // cardinality: exactly 1
+ // file which is associated with the snippet
+ _, err := parser.getFileFromNode(siTriple.Object)
+ if err != nil {
+ return nil, err
+ }
+ docElemID, err := ExtractDocElementID(getLastPartOfURI(siTriple.Object.ID))
+ si.SnippetFromFileSPDXIdentifier = docElemID.ElementRefID
+ case SPDX_RANGE:
+ // cardinality: min 1
+ err = parser.setSnippetRangeFromNode(siTriple.Object, si)
+ if err != nil {
+ return nil, err
+ }
+ case SPDX_LICENSE_INFO_IN_SNIPPET:
+ // license info in snippet can be NONE, NOASSERTION or SimpleLicensingInfo
+ // using AnyLicenseInfo because it can redirect the request and
+ // can handle NONE & NOASSERTION
+ var anyLicense AnyLicenseInfo
+ anyLicense, err = parser.getAnyLicenseFromNode(siTriple.Object)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing license info in snippet: %v", err)
+ }
+ si.LicenseInfoInSnippet = append(si.LicenseInfoInSnippet, anyLicense.ToLicenseString())
+ case SPDX_NAME:
+ si.SnippetName = siTriple.Object.ID
+ case SPDX_COPYRIGHT_TEXT:
+ si.SnippetCopyrightText = siTriple.Object.ID
+ case SPDX_LICENSE_COMMENTS:
+ si.SnippetLicenseComments = siTriple.Object.ID
+ case RDFS_COMMENT:
+ si.SnippetComment = siTriple.Object.ID
+ case SPDX_LICENSE_CONCLUDED:
+ var anyLicense AnyLicenseInfo
+ anyLicense, err = parser.getAnyLicenseFromNode(siTriple.Object)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing license info in snippet: %v", err)
+ }
+ si.SnippetLicenseConcluded = anyLicense.ToLicenseString()
+ default:
+ return nil, fmt.Errorf("unknown predicate %v", siTriple.Predicate.ID)
+ }
+ }
+ return si, nil
+}
+
+// given is the id of the file, sets the snippet to the file in parser.
+func (parser *rdfParser2_3) setSnippetToFileWithID(snippet *v2_3.Snippet, fileID common.ElementID) error {
+ if parser.files[fileID] == nil {
+ return fmt.Errorf("snippet refers to an undefined file with ID: %s", fileID)
+ }
+
+ // initializing snippet of the files if it is not defined already
+ if parser.files[fileID].Snippets == nil {
+ parser.files[fileID].Snippets = map[common.ElementID]*v2_3.Snippet{}
+ }
+
+ // setting the snippet to the file.
+ parser.files[fileID].Snippets[snippet.SnippetSPDXIdentifier] = snippet
+
+ return nil
+}
+
+func (parser *rdfParser2_3) setSnippetRangeFromNode(node *gordfParser.Node, si *v2_3.Snippet) error {
+ // for a range object, we can have only 3 associated triples:
+ // node -> RDF_TYPE -> Object
+ // node -> startPointer -> Object
+ // node -> endPointer -> Object
+ associatedTriples := parser.nodeToTriples(node)
+ if len(associatedTriples) != 3 {
+ return fmt.Errorf("range should be associated with exactly 3 triples, got %d", len(associatedTriples))
+ }
+
+ // Triple 1: Predicate=RDF_TYPE
+ typeTriple := rdfwriter.FilterTriples(associatedTriples, &node.ID, &RDF_TYPE, nil)
+ if len(typeTriple) != 1 {
+ // we had 3 associated triples. out of which 2 is start and end pointer,
+ // if we do not have the rdf:type triple as the third one,
+ // we have either extra or undefined predicate.
+ return fmt.Errorf("every object node must be associated with exactly one rdf:type triple, found: %d", len(typeTriple))
+ }
+
+ // getting start pointer
+ startPointerTriples := rdfwriter.FilterTriples(associatedTriples, &node.ID, &PTR_START_POINTER, nil)
+ if len(startPointerTriples) != 1 {
+ return fmt.Errorf("range object must be associated with exactly 1 startPointer, got %d", len(startPointerTriples))
+ }
+ startRangeType, start, err := parser.getPointerFromNode(startPointerTriples[0].Object, si)
+ if err != nil {
+ return fmt.Errorf("error parsing startPointer: %v", err)
+ }
+
+ // getting end pointer
+ endPointerTriples := rdfwriter.FilterTriples(associatedTriples, &node.ID, &PTR_END_POINTER, nil)
+ if len(startPointerTriples) != 1 {
+ return fmt.Errorf("range object must be associated with exactly 1 endPointer, got %d", len(endPointerTriples))
+ }
+ endRangeType, end, err := parser.getPointerFromNode(endPointerTriples[0].Object, si)
+ if err != nil {
+ return fmt.Errorf("error parsing endPointer: %v", err)
+ }
+
+ // return error when start and end pointer type is not same.
+ if startRangeType != endRangeType {
+ return fmt.Errorf("start and end range type doesn't match")
+ }
+
+ si.Ranges = []common.SnippetRange{{
+ StartPointer: common.SnippetRangePointer{FileSPDXIdentifier: si.SnippetFromFileSPDXIdentifier},
+ EndPointer: common.SnippetRangePointer{FileSPDXIdentifier: si.SnippetFromFileSPDXIdentifier},
+ }}
+
+ if startRangeType == LINE_RANGE {
+ si.Ranges[0].StartPointer.LineNumber = start
+ si.Ranges[0].EndPointer.LineNumber = end
+ } else {
+ si.Ranges[0].StartPointer.Offset = start
+ si.Ranges[0].EndPointer.Offset = end
+ }
+ return nil
+}
+
+func (parser *rdfParser2_3) getPointerFromNode(node *gordfParser.Node, si *v2_3.Snippet) (rt RangeType, number int, err error) {
+ for _, triple := range parser.nodeToTriples(node) {
+ switch triple.Predicate.ID {
+ case RDF_TYPE:
+ case PTR_REFERENCE:
+ err = parser.parseRangeReference(triple.Object, si)
+ case PTR_OFFSET:
+ number, err = strconv.Atoi(triple.Object.ID)
+ rt = BYTE_RANGE
+ case PTR_LINE_NUMBER:
+ number, err = strconv.Atoi(triple.Object.ID)
+ rt = LINE_RANGE
+ default:
+ err = fmt.Errorf("undefined predicate (%s) for a pointer", triple.Predicate)
+ }
+ if err != nil {
+ return
+ }
+ }
+ if rt == "" {
+ err = fmt.Errorf("range type not defined for a pointer")
+ }
+ return
+}
+
+func (parser *rdfParser2_3) parseRangeReference(node *gordfParser.Node, snippet *v2_3.Snippet) error {
+ // reference is supposed to be either a resource reference to an already
+ // defined or a new file. Unfortunately, I didn't find field where this can be set in the tools-golang data model.
+ // todo: set this reference to the snippet
+ associatedTriples := rdfwriter.FilterTriples(parser.gordfParserObj.Triples, &node.ID, nil, nil)
+ if len(associatedTriples) == 0 {
+ return nil
+ }
+ _, err := parser.getFileFromNode(node)
+ if err != nil {
+ return fmt.Errorf("error parsing a new file in a reference: %v", err)
+ }
+ return nil
+}
+
+func setSnippetID(uri string, si *v2_3.Snippet) (err error) {
+ fragment := getLastPartOfURI(uri)
+ si.SnippetSPDXIdentifier, err = ExtractElementID(fragment)
+ if err != nil {
+ return fmt.Errorf("error setting snippet identifier: %v", uri)
+ }
+ return nil
+}