diff options
Diffstat (limited to 'tvloader/parser2v3/parse_package.go')
-rw-r--r-- | tvloader/parser2v3/parse_package.go | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/tvloader/parser2v3/parse_package.go b/tvloader/parser2v3/parse_package.go new file mode 100644 index 0000000..989261d --- /dev/null +++ b/tvloader/parser2v3/parse_package.go @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +package parser2v3 + +import ( + "fmt" + "strings" + + "github.com/spdx/tools-golang/spdx/common" + "github.com/spdx/tools-golang/spdx/v2_3" +) + +func (parser *tvParser2_3) parsePairFromPackage2_3(tag string, value string) error { + // expire pkgExtRef for anything other than a comment + // (we'll actually handle the comment further below) + if tag != "ExternalRefComment" { + parser.pkgExtRef = nil + } + + switch tag { + case "PackageName": + // if package already has a name, create and go on to a new package + if parser.pkg == nil || parser.pkg.PackageName != "" { + // check if the previous package contained an spdx Id or not + if parser.pkg != nil && parser.pkg.PackageSPDXIdentifier == nullSpdxElementId2_3 { + return fmt.Errorf("package with PackageName %s does not have SPDX identifier", parser.pkg.PackageName) + } + parser.pkg = &v2_3.Package{ + FilesAnalyzed: true, + IsFilesAnalyzedTagPresent: false, + } + } + parser.pkg.PackageName = value + // tag for going on to file section + case "FileName": + parser.st = psFile2_3 + return parser.parsePairFromFile2_3(tag, value) + // tag for going on to other license section + case "LicenseID": + parser.st = psOtherLicense2_3 + return parser.parsePairFromOtherLicense2_3(tag, value) + case "SPDXID": + eID, err := extractElementID(value) + if err != nil { + return err + } + parser.pkg.PackageSPDXIdentifier = eID + if parser.doc.Packages == nil { + parser.doc.Packages = []*v2_3.Package{} + } + parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + case "PackageVersion": + parser.pkg.PackageVersion = value + case "PackageFileName": + parser.pkg.PackageFileName = value + case "PackageSupplier": + supplier := &common.Supplier{Supplier: value} + if value == "NOASSERTION" { + parser.pkg.PackageSupplier = supplier + break + } + + subkey, subvalue, err := extractSubs(value) + if err != nil { + return err + } + switch subkey { + case "Person", "Organization": + supplier.Supplier = subvalue + supplier.SupplierType = subkey + default: + return fmt.Errorf("unrecognized PackageSupplier type %v", subkey) + } + parser.pkg.PackageSupplier = supplier + case "PackageOriginator": + originator := &common.Originator{Originator: value} + if value == "NOASSERTION" { + parser.pkg.PackageOriginator = originator + break + } + + subkey, subvalue, err := extractSubs(value) + if err != nil { + return err + } + switch subkey { + case "Person", "Organization": + originator.Originator = subvalue + originator.OriginatorType = subkey + default: + return fmt.Errorf("unrecognized PackageOriginator type %v", subkey) + } + parser.pkg.PackageOriginator = originator + case "PackageDownloadLocation": + parser.pkg.PackageDownloadLocation = value + case "FilesAnalyzed": + parser.pkg.IsFilesAnalyzedTagPresent = true + if value == "false" { + parser.pkg.FilesAnalyzed = false + } else if value == "true" { + parser.pkg.FilesAnalyzed = true + } + case "PackageVerificationCode": + parser.pkg.PackageVerificationCode = extractCodeAndExcludes(value) + case "PackageChecksum": + subkey, subvalue, err := extractSubs(value) + if err != nil { + return err + } + if parser.pkg.PackageChecksums == nil { + parser.pkg.PackageChecksums = []common.Checksum{} + } + switch common.ChecksumAlgorithm(subkey) { + case common.SHA1, + common.SHA224, + common.SHA256, + common.SHA384, + common.SHA512, + common.MD2, + common.MD4, + common.MD5, + common.MD6, + common.SHA3_256, + common.SHA3_384, + common.SHA3_512, + common.BLAKE2b_256, + common.BLAKE2b_384, + common.BLAKE2b_512, + common.BLAKE3, + common.ADLER32: + algorithm := common.ChecksumAlgorithm(subkey) + parser.pkg.PackageChecksums = append(parser.pkg.PackageChecksums, common.Checksum{Algorithm: algorithm, Value: subvalue}) + default: + return fmt.Errorf("got unknown checksum type %s", subkey) + } + case "PackageHomePage": + parser.pkg.PackageHomePage = value + case "PackageSourceInfo": + parser.pkg.PackageSourceInfo = value + case "PackageLicenseConcluded": + parser.pkg.PackageLicenseConcluded = value + case "PackageLicenseInfoFromFiles": + parser.pkg.PackageLicenseInfoFromFiles = append(parser.pkg.PackageLicenseInfoFromFiles, value) + case "PackageLicenseDeclared": + parser.pkg.PackageLicenseDeclared = value + case "PackageLicenseComments": + parser.pkg.PackageLicenseComments = value + case "PackageCopyrightText": + parser.pkg.PackageCopyrightText = value + case "PackageSummary": + parser.pkg.PackageSummary = value + case "PackageDescription": + parser.pkg.PackageDescription = value + case "PackageComment": + parser.pkg.PackageComment = value + case "PrimaryPackagePurpose": + parser.pkg.PrimaryPackagePurpose = value + case "ReleaseDate": + parser.pkg.ReleaseDate = value + case "BuiltDate": + parser.pkg.BuiltDate = value + case "ValidUntilDate": + parser.pkg.ValidUntilDate = value + case "PackageAttributionText": + parser.pkg.PackageAttributionTexts = append(parser.pkg.PackageAttributionTexts, value) + case "ExternalRef": + parser.pkgExtRef = &v2_3.PackageExternalReference{} + parser.pkg.PackageExternalReferences = append(parser.pkg.PackageExternalReferences, parser.pkgExtRef) + category, refType, locator, err := extractPackageExternalReference(value) + if err != nil { + return err + } + parser.pkgExtRef.Category = category + parser.pkgExtRef.RefType = refType + parser.pkgExtRef.Locator = locator + case "ExternalRefComment": + if parser.pkgExtRef == nil { + return fmt.Errorf("no current ExternalRef found") + } + parser.pkgExtRef.ExternalRefComment = value + // now, expire pkgExtRef anyway because it can have at most one comment + parser.pkgExtRef = nil + // for relationship tags, pass along but don't change state + case "Relationship": + parser.rln = &v2_3.Relationship{} + parser.doc.Relationships = append(parser.doc.Relationships, parser.rln) + return parser.parsePairForRelationship2_3(tag, value) + case "RelationshipComment": + return parser.parsePairForRelationship2_3(tag, value) + // for annotation tags, pass along but don't change state + case "Annotator": + parser.ann = &v2_3.Annotation{} + parser.doc.Annotations = append(parser.doc.Annotations, parser.ann) + return parser.parsePairForAnnotation2_3(tag, value) + case "AnnotationDate": + return parser.parsePairForAnnotation2_3(tag, value) + case "AnnotationType": + return parser.parsePairForAnnotation2_3(tag, value) + case "SPDXREF": + return parser.parsePairForAnnotation2_3(tag, value) + case "AnnotationComment": + return parser.parsePairForAnnotation2_3(tag, value) + // tag for going on to review section (DEPRECATED) + case "Reviewer": + parser.st = psReview2_3 + return parser.parsePairFromReview2_3(tag, value) + default: + return fmt.Errorf("received unknown tag %v in Package section", tag) + } + + return nil +} + +// ===== Helper functions ===== + +func extractCodeAndExcludes(value string) *common.PackageVerificationCode { + // FIXME this should probably be done using regular expressions instead + // split by paren + word "excludes:" + sp := strings.SplitN(value, "(excludes:", 2) + if len(sp) < 2 { + // not found; return the whole string as just the code + return &common.PackageVerificationCode{Value: value, ExcludedFiles: []string{}} + } + + // if we're here, code is in first part and excludes filename is in + // second part, with trailing paren + code := strings.TrimSpace(sp[0]) + parsedSp := strings.SplitN(sp[1], ")", 2) + fileName := strings.TrimSpace(parsedSp[0]) + return &common.PackageVerificationCode{Value: code, ExcludedFiles: []string{fileName}} +} + +func extractPackageExternalReference(value string) (string, string, string, error) { + sp := strings.Split(value, " ") + // remove any that are just whitespace + keepSp := []string{} + for _, s := range sp { + ss := strings.TrimSpace(s) + if ss != "" { + keepSp = append(keepSp, ss) + } + } + // now, should have 3 items and should be able to map them + if len(keepSp) != 3 { + return "", "", "", fmt.Errorf("expected 3 elements, got %d", len(keepSp)) + } + return keepSp[0], keepSp[1], keepSp[2], nil +} |