xref: /aosp_15_r20/external/spdx-tools/tvloader/parser2v1/parse_package.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2*ba677afaSXin Li
3*ba677afaSXin Lipackage parser2v1
4*ba677afaSXin Li
5*ba677afaSXin Liimport (
6*ba677afaSXin Li	"fmt"
7*ba677afaSXin Li	"strings"
8*ba677afaSXin Li
9*ba677afaSXin Li	"github.com/spdx/tools-golang/spdx/common"
10*ba677afaSXin Li	"github.com/spdx/tools-golang/spdx/v2_1"
11*ba677afaSXin Li)
12*ba677afaSXin Li
13*ba677afaSXin Lifunc (parser *tvParser2_1) parsePairFromPackage2_1(tag string, value string) error {
14*ba677afaSXin Li	// expire pkgExtRef for anything other than a comment
15*ba677afaSXin Li	// (we'll actually handle the comment further below)
16*ba677afaSXin Li	if tag != "ExternalRefComment" {
17*ba677afaSXin Li		parser.pkgExtRef = nil
18*ba677afaSXin Li	}
19*ba677afaSXin Li
20*ba677afaSXin Li	switch tag {
21*ba677afaSXin Li	case "PackageName":
22*ba677afaSXin Li		// if package already has a name, create and go on to a new package
23*ba677afaSXin Li		if parser.pkg == nil || parser.pkg.PackageName != "" {
24*ba677afaSXin Li			// check if the previous package contained an spdxId or not
25*ba677afaSXin Li			if parser.pkg != nil && parser.pkg.PackageSPDXIdentifier == nullSpdxElementId2_1 {
26*ba677afaSXin Li				return fmt.Errorf("package with PackageName %s does not have SPDX identifier", parser.pkg.PackageName)
27*ba677afaSXin Li			}
28*ba677afaSXin Li			parser.pkg = &v2_1.Package{
29*ba677afaSXin Li				FilesAnalyzed:             true,
30*ba677afaSXin Li				IsFilesAnalyzedTagPresent: false,
31*ba677afaSXin Li			}
32*ba677afaSXin Li		}
33*ba677afaSXin Li		parser.pkg.PackageName = value
34*ba677afaSXin Li	// tag for going on to file section
35*ba677afaSXin Li	case "FileName":
36*ba677afaSXin Li		parser.st = psFile2_1
37*ba677afaSXin Li		return parser.parsePairFromFile2_1(tag, value)
38*ba677afaSXin Li	// tag for going on to other license section
39*ba677afaSXin Li	case "LicenseID":
40*ba677afaSXin Li		parser.st = psOtherLicense2_1
41*ba677afaSXin Li		return parser.parsePairFromOtherLicense2_1(tag, value)
42*ba677afaSXin Li	case "SPDXID":
43*ba677afaSXin Li		eID, err := extractElementID(value)
44*ba677afaSXin Li		if err != nil {
45*ba677afaSXin Li			return err
46*ba677afaSXin Li		}
47*ba677afaSXin Li		parser.pkg.PackageSPDXIdentifier = eID
48*ba677afaSXin Li		if parser.doc.Packages == nil {
49*ba677afaSXin Li			parser.doc.Packages = []*v2_1.Package{}
50*ba677afaSXin Li		}
51*ba677afaSXin Li		parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
52*ba677afaSXin Li	case "PackageVersion":
53*ba677afaSXin Li		parser.pkg.PackageVersion = value
54*ba677afaSXin Li	case "PackageFileName":
55*ba677afaSXin Li		parser.pkg.PackageFileName = value
56*ba677afaSXin Li	case "PackageSupplier":
57*ba677afaSXin Li		parser.pkg.PackageSupplier = &common.Supplier{}
58*ba677afaSXin Li		if value == "NOASSERTION" {
59*ba677afaSXin Li			parser.pkg.PackageSupplier.Supplier = value
60*ba677afaSXin Li			break
61*ba677afaSXin Li		}
62*ba677afaSXin Li		subkey, subvalue, err := extractSubs(value)
63*ba677afaSXin Li		if err != nil {
64*ba677afaSXin Li			return err
65*ba677afaSXin Li		}
66*ba677afaSXin Li		switch subkey {
67*ba677afaSXin Li		case "Person", "Organization":
68*ba677afaSXin Li			parser.pkg.PackageSupplier.Supplier = subvalue
69*ba677afaSXin Li			parser.pkg.PackageSupplier.SupplierType = subkey
70*ba677afaSXin Li		default:
71*ba677afaSXin Li			return fmt.Errorf("unrecognized PackageSupplier type %v", subkey)
72*ba677afaSXin Li		}
73*ba677afaSXin Li	case "PackageOriginator":
74*ba677afaSXin Li		parser.pkg.PackageOriginator = &common.Originator{}
75*ba677afaSXin Li		if value == "NOASSERTION" {
76*ba677afaSXin Li			parser.pkg.PackageOriginator.Originator = value
77*ba677afaSXin Li			break
78*ba677afaSXin Li		}
79*ba677afaSXin Li		subkey, subvalue, err := extractSubs(value)
80*ba677afaSXin Li		if err != nil {
81*ba677afaSXin Li			return err
82*ba677afaSXin Li		}
83*ba677afaSXin Li		switch subkey {
84*ba677afaSXin Li		case "Person", "Organization":
85*ba677afaSXin Li			parser.pkg.PackageOriginator.Originator = subvalue
86*ba677afaSXin Li			parser.pkg.PackageOriginator.OriginatorType = subkey
87*ba677afaSXin Li		default:
88*ba677afaSXin Li			return fmt.Errorf("unrecognized PackageOriginator type %v", subkey)
89*ba677afaSXin Li		}
90*ba677afaSXin Li	case "PackageDownloadLocation":
91*ba677afaSXin Li		parser.pkg.PackageDownloadLocation = value
92*ba677afaSXin Li	case "FilesAnalyzed":
93*ba677afaSXin Li		parser.pkg.IsFilesAnalyzedTagPresent = true
94*ba677afaSXin Li		if value == "false" {
95*ba677afaSXin Li			parser.pkg.FilesAnalyzed = false
96*ba677afaSXin Li		} else if value == "true" {
97*ba677afaSXin Li			parser.pkg.FilesAnalyzed = true
98*ba677afaSXin Li		}
99*ba677afaSXin Li	case "PackageVerificationCode":
100*ba677afaSXin Li		parser.pkg.PackageVerificationCode = extractCodeAndExcludes(value)
101*ba677afaSXin Li	case "PackageChecksum":
102*ba677afaSXin Li		subkey, subvalue, err := extractSubs(value)
103*ba677afaSXin Li		if err != nil {
104*ba677afaSXin Li			return err
105*ba677afaSXin Li		}
106*ba677afaSXin Li		if parser.pkg.PackageChecksums == nil {
107*ba677afaSXin Li			parser.pkg.PackageChecksums = []common.Checksum{}
108*ba677afaSXin Li		}
109*ba677afaSXin Li		switch common.ChecksumAlgorithm(subkey) {
110*ba677afaSXin Li		case common.SHA1, common.SHA256, common.MD5:
111*ba677afaSXin Li			algorithm := common.ChecksumAlgorithm(subkey)
112*ba677afaSXin Li			parser.pkg.PackageChecksums = append(parser.pkg.PackageChecksums, common.Checksum{Algorithm: algorithm, Value: subvalue})
113*ba677afaSXin Li		default:
114*ba677afaSXin Li			return fmt.Errorf("got unknown checksum type %s", subkey)
115*ba677afaSXin Li		}
116*ba677afaSXin Li	case "PackageHomePage":
117*ba677afaSXin Li		parser.pkg.PackageHomePage = value
118*ba677afaSXin Li	case "PackageSourceInfo":
119*ba677afaSXin Li		parser.pkg.PackageSourceInfo = value
120*ba677afaSXin Li	case "PackageLicenseConcluded":
121*ba677afaSXin Li		parser.pkg.PackageLicenseConcluded = value
122*ba677afaSXin Li	case "PackageLicenseInfoFromFiles":
123*ba677afaSXin Li		parser.pkg.PackageLicenseInfoFromFiles = append(parser.pkg.PackageLicenseInfoFromFiles, value)
124*ba677afaSXin Li	case "PackageLicenseDeclared":
125*ba677afaSXin Li		parser.pkg.PackageLicenseDeclared = value
126*ba677afaSXin Li	case "PackageLicenseComments":
127*ba677afaSXin Li		parser.pkg.PackageLicenseComments = value
128*ba677afaSXin Li	case "PackageCopyrightText":
129*ba677afaSXin Li		parser.pkg.PackageCopyrightText = value
130*ba677afaSXin Li	case "PackageSummary":
131*ba677afaSXin Li		parser.pkg.PackageSummary = value
132*ba677afaSXin Li	case "PackageDescription":
133*ba677afaSXin Li		parser.pkg.PackageDescription = value
134*ba677afaSXin Li	case "PackageComment":
135*ba677afaSXin Li		parser.pkg.PackageComment = value
136*ba677afaSXin Li	case "ExternalRef":
137*ba677afaSXin Li		parser.pkgExtRef = &v2_1.PackageExternalReference{}
138*ba677afaSXin Li		parser.pkg.PackageExternalReferences = append(parser.pkg.PackageExternalReferences, parser.pkgExtRef)
139*ba677afaSXin Li		category, refType, locator, err := extractPackageExternalReference(value)
140*ba677afaSXin Li		if err != nil {
141*ba677afaSXin Li			return err
142*ba677afaSXin Li		}
143*ba677afaSXin Li		parser.pkgExtRef.Category = category
144*ba677afaSXin Li		parser.pkgExtRef.RefType = refType
145*ba677afaSXin Li		parser.pkgExtRef.Locator = locator
146*ba677afaSXin Li	case "ExternalRefComment":
147*ba677afaSXin Li		if parser.pkgExtRef == nil {
148*ba677afaSXin Li			return fmt.Errorf("no current ExternalRef found")
149*ba677afaSXin Li		}
150*ba677afaSXin Li		parser.pkgExtRef.ExternalRefComment = value
151*ba677afaSXin Li		// now, expire pkgExtRef anyway because it can have at most one comment
152*ba677afaSXin Li		parser.pkgExtRef = nil
153*ba677afaSXin Li	// for relationship tags, pass along but don't change state
154*ba677afaSXin Li	case "Relationship":
155*ba677afaSXin Li		parser.rln = &v2_1.Relationship{}
156*ba677afaSXin Li		parser.doc.Relationships = append(parser.doc.Relationships, parser.rln)
157*ba677afaSXin Li		return parser.parsePairForRelationship2_1(tag, value)
158*ba677afaSXin Li	case "RelationshipComment":
159*ba677afaSXin Li		return parser.parsePairForRelationship2_1(tag, value)
160*ba677afaSXin Li	// for annotation tags, pass along but don't change state
161*ba677afaSXin Li	case "Annotator":
162*ba677afaSXin Li		parser.ann = &v2_1.Annotation{}
163*ba677afaSXin Li		parser.doc.Annotations = append(parser.doc.Annotations, parser.ann)
164*ba677afaSXin Li		return parser.parsePairForAnnotation2_1(tag, value)
165*ba677afaSXin Li	case "AnnotationDate":
166*ba677afaSXin Li		return parser.parsePairForAnnotation2_1(tag, value)
167*ba677afaSXin Li	case "AnnotationType":
168*ba677afaSXin Li		return parser.parsePairForAnnotation2_1(tag, value)
169*ba677afaSXin Li	case "SPDXREF":
170*ba677afaSXin Li		return parser.parsePairForAnnotation2_1(tag, value)
171*ba677afaSXin Li	case "AnnotationComment":
172*ba677afaSXin Li		return parser.parsePairForAnnotation2_1(tag, value)
173*ba677afaSXin Li	// tag for going on to review section (DEPRECATED)
174*ba677afaSXin Li	case "Reviewer":
175*ba677afaSXin Li		parser.st = psReview2_1
176*ba677afaSXin Li		return parser.parsePairFromReview2_1(tag, value)
177*ba677afaSXin Li	default:
178*ba677afaSXin Li		return fmt.Errorf("received unknown tag %v in Package section", tag)
179*ba677afaSXin Li	}
180*ba677afaSXin Li
181*ba677afaSXin Li	return nil
182*ba677afaSXin Li}
183*ba677afaSXin Li
184*ba677afaSXin Li// ===== Helper functions =====
185*ba677afaSXin Li
186*ba677afaSXin Lifunc extractCodeAndExcludes(value string) common.PackageVerificationCode {
187*ba677afaSXin Li	// FIXME this should probably be done using regular expressions instead
188*ba677afaSXin Li	// split by paren + word "excludes:"
189*ba677afaSXin Li	sp := strings.SplitN(value, "(excludes:", 2)
190*ba677afaSXin Li	if len(sp) < 2 {
191*ba677afaSXin Li		// not found; return the whole string as just the code
192*ba677afaSXin Li		return common.PackageVerificationCode{Value: value, ExcludedFiles: []string{}}
193*ba677afaSXin Li	}
194*ba677afaSXin Li
195*ba677afaSXin Li	// if we're here, code is in first part and excludes filename is in
196*ba677afaSXin Li	// second part, with trailing paren
197*ba677afaSXin Li	code := strings.TrimSpace(sp[0])
198*ba677afaSXin Li	parsedSp := strings.SplitN(sp[1], ")", 2)
199*ba677afaSXin Li	fileName := strings.TrimSpace(parsedSp[0])
200*ba677afaSXin Li	return common.PackageVerificationCode{Value: code, ExcludedFiles: []string{fileName}}
201*ba677afaSXin Li}
202*ba677afaSXin Li
203*ba677afaSXin Lifunc extractPackageExternalReference(value string) (string, string, string, error) {
204*ba677afaSXin Li	sp := strings.Split(value, " ")
205*ba677afaSXin Li	// remove any that are just whitespace
206*ba677afaSXin Li	keepSp := []string{}
207*ba677afaSXin Li	for _, s := range sp {
208*ba677afaSXin Li		ss := strings.TrimSpace(s)
209*ba677afaSXin Li		if ss != "" {
210*ba677afaSXin Li			keepSp = append(keepSp, ss)
211*ba677afaSXin Li		}
212*ba677afaSXin Li	}
213*ba677afaSXin Li	// now, should have 3 items and should be able to map them
214*ba677afaSXin Li	if len(keepSp) != 3 {
215*ba677afaSXin Li		return "", "", "", fmt.Errorf("expected 3 elements, got %d", len(keepSp))
216*ba677afaSXin Li	}
217*ba677afaSXin Li	return keepSp[0], keepSp[1], keepSp[2], nil
218*ba677afaSXin Li}
219