xref: /aosp_15_r20/external/spdx-tools/tvloader/parser2v3/parser.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1*ba677afaSXin Li// Package parser2v3 contains functions to read, load and parse
2*ba677afaSXin Li// SPDX tag-value files, version 2.3.
3*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
4*ba677afaSXin Lipackage parser2v3
5*ba677afaSXin Li
6*ba677afaSXin Liimport (
7*ba677afaSXin Li	"fmt"
8*ba677afaSXin Li
9*ba677afaSXin Li	"github.com/spdx/tools-golang/spdx/common"
10*ba677afaSXin Li	"github.com/spdx/tools-golang/spdx/v2_3"
11*ba677afaSXin Li	"github.com/spdx/tools-golang/tvloader/reader"
12*ba677afaSXin Li)
13*ba677afaSXin Li
14*ba677afaSXin Li// ParseTagValues takes a list of (tag, value) pairs, parses it and returns
15*ba677afaSXin Li// a pointer to a parsed SPDX Document.
16*ba677afaSXin Lifunc ParseTagValues(tvs []reader.TagValuePair) (*v2_3.Document, error) {
17*ba677afaSXin Li	parser := tvParser2_3{}
18*ba677afaSXin Li	for _, tv := range tvs {
19*ba677afaSXin Li		err := parser.parsePair2_3(tv.Tag, tv.Value)
20*ba677afaSXin Li		if err != nil {
21*ba677afaSXin Li			return nil, err
22*ba677afaSXin Li		}
23*ba677afaSXin Li	}
24*ba677afaSXin Li	if parser.file != nil && parser.file.FileSPDXIdentifier == nullSpdxElementId2_3 {
25*ba677afaSXin Li		return nil, fmt.Errorf("file with FileName %s does not have SPDX identifier", parser.file.FileName)
26*ba677afaSXin Li	}
27*ba677afaSXin Li	if parser.pkg != nil && parser.pkg.PackageSPDXIdentifier == nullSpdxElementId2_3 {
28*ba677afaSXin Li		return nil, fmt.Errorf("package with PackageName %s does not have SPDX identifier", parser.pkg.PackageName)
29*ba677afaSXin Li	}
30*ba677afaSXin Li	return parser.doc, nil
31*ba677afaSXin Li}
32*ba677afaSXin Li
33*ba677afaSXin Lifunc (parser *tvParser2_3) parsePair2_3(tag string, value string) error {
34*ba677afaSXin Li	switch parser.st {
35*ba677afaSXin Li	case psStart2_3:
36*ba677afaSXin Li		return parser.parsePairFromStart2_3(tag, value)
37*ba677afaSXin Li	case psCreationInfo2_3:
38*ba677afaSXin Li		return parser.parsePairFromCreationInfo2_3(tag, value)
39*ba677afaSXin Li	case psPackage2_3:
40*ba677afaSXin Li		return parser.parsePairFromPackage2_3(tag, value)
41*ba677afaSXin Li	case psFile2_3:
42*ba677afaSXin Li		return parser.parsePairFromFile2_3(tag, value)
43*ba677afaSXin Li	case psSnippet2_3:
44*ba677afaSXin Li		return parser.parsePairFromSnippet2_3(tag, value)
45*ba677afaSXin Li	case psOtherLicense2_3:
46*ba677afaSXin Li		return parser.parsePairFromOtherLicense2_3(tag, value)
47*ba677afaSXin Li	case psReview2_3:
48*ba677afaSXin Li		return parser.parsePairFromReview2_3(tag, value)
49*ba677afaSXin Li	default:
50*ba677afaSXin Li		return fmt.Errorf("parser state %v not recognized when parsing (%s, %s)", parser.st, tag, value)
51*ba677afaSXin Li	}
52*ba677afaSXin Li}
53*ba677afaSXin Li
54*ba677afaSXin Lifunc (parser *tvParser2_3) parsePairFromStart2_3(tag string, value string) error {
55*ba677afaSXin Li	// fail if not in Start parser state
56*ba677afaSXin Li	if parser.st != psStart2_3 {
57*ba677afaSXin Li		return fmt.Errorf("got invalid state %v in parsePairFromStart2_3", parser.st)
58*ba677afaSXin Li	}
59*ba677afaSXin Li
60*ba677afaSXin Li	// create an SPDX Document data struct if we don't have one already
61*ba677afaSXin Li	if parser.doc == nil {
62*ba677afaSXin Li		parser.doc = &v2_3.Document{ExternalDocumentReferences: []v2_3.ExternalDocumentRef{}}
63*ba677afaSXin Li	}
64*ba677afaSXin Li
65*ba677afaSXin Li	switch tag {
66*ba677afaSXin Li	case "DocumentComment":
67*ba677afaSXin Li		parser.doc.DocumentComment = value
68*ba677afaSXin Li	case "SPDXVersion":
69*ba677afaSXin Li		parser.doc.SPDXVersion = value
70*ba677afaSXin Li	case "DataLicense":
71*ba677afaSXin Li		parser.doc.DataLicense = value
72*ba677afaSXin Li	case "SPDXID":
73*ba677afaSXin Li		eID, err := extractElementID(value)
74*ba677afaSXin Li		if err != nil {
75*ba677afaSXin Li			return err
76*ba677afaSXin Li		}
77*ba677afaSXin Li		parser.doc.SPDXIdentifier = eID
78*ba677afaSXin Li	case "DocumentName":
79*ba677afaSXin Li		parser.doc.DocumentName = value
80*ba677afaSXin Li	case "DocumentNamespace":
81*ba677afaSXin Li		parser.doc.DocumentNamespace = value
82*ba677afaSXin Li	case "ExternalDocumentRef":
83*ba677afaSXin Li		documentRefID, uri, alg, checksum, err := extractExternalDocumentReference(value)
84*ba677afaSXin Li		if err != nil {
85*ba677afaSXin Li			return err
86*ba677afaSXin Li		}
87*ba677afaSXin Li		edr := v2_3.ExternalDocumentRef{
88*ba677afaSXin Li			DocumentRefID: documentRefID,
89*ba677afaSXin Li			URI:           uri,
90*ba677afaSXin Li			Checksum:      common.Checksum{Algorithm: common.ChecksumAlgorithm(alg), Value: checksum},
91*ba677afaSXin Li		}
92*ba677afaSXin Li		parser.doc.ExternalDocumentReferences = append(parser.doc.ExternalDocumentReferences, edr)
93*ba677afaSXin Li	default:
94*ba677afaSXin Li		// move to Creation Info parser state
95*ba677afaSXin Li		parser.st = psCreationInfo2_3
96*ba677afaSXin Li		return parser.parsePairFromCreationInfo2_3(tag, value)
97*ba677afaSXin Li	}
98*ba677afaSXin Li
99*ba677afaSXin Li	return nil
100*ba677afaSXin Li}
101