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 "strings" 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) 12*ba677afaSXin Li 13*ba677afaSXin Lifunc (parser *tvParser2_3) parsePairFromPackage2_3(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 spdx Id or not 25*ba677afaSXin Li if parser.pkg != nil && parser.pkg.PackageSPDXIdentifier == nullSpdxElementId2_3 { 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_3.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_3 37*ba677afaSXin Li return parser.parsePairFromFile2_3(tag, value) 38*ba677afaSXin Li // tag for going on to other license section 39*ba677afaSXin Li case "LicenseID": 40*ba677afaSXin Li parser.st = psOtherLicense2_3 41*ba677afaSXin Li return parser.parsePairFromOtherLicense2_3(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_3.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 supplier := &common.Supplier{Supplier: value} 58*ba677afaSXin Li if value == "NOASSERTION" { 59*ba677afaSXin Li parser.pkg.PackageSupplier = supplier 60*ba677afaSXin Li break 61*ba677afaSXin Li } 62*ba677afaSXin Li 63*ba677afaSXin Li subkey, subvalue, err := extractSubs(value) 64*ba677afaSXin Li if err != nil { 65*ba677afaSXin Li return err 66*ba677afaSXin Li } 67*ba677afaSXin Li switch subkey { 68*ba677afaSXin Li case "Person", "Organization": 69*ba677afaSXin Li supplier.Supplier = subvalue 70*ba677afaSXin Li supplier.SupplierType = subkey 71*ba677afaSXin Li default: 72*ba677afaSXin Li return fmt.Errorf("unrecognized PackageSupplier type %v", subkey) 73*ba677afaSXin Li } 74*ba677afaSXin Li parser.pkg.PackageSupplier = supplier 75*ba677afaSXin Li case "PackageOriginator": 76*ba677afaSXin Li originator := &common.Originator{Originator: value} 77*ba677afaSXin Li if value == "NOASSERTION" { 78*ba677afaSXin Li parser.pkg.PackageOriginator = originator 79*ba677afaSXin Li break 80*ba677afaSXin Li } 81*ba677afaSXin Li 82*ba677afaSXin Li subkey, subvalue, err := extractSubs(value) 83*ba677afaSXin Li if err != nil { 84*ba677afaSXin Li return err 85*ba677afaSXin Li } 86*ba677afaSXin Li switch subkey { 87*ba677afaSXin Li case "Person", "Organization": 88*ba677afaSXin Li originator.Originator = subvalue 89*ba677afaSXin Li originator.OriginatorType = subkey 90*ba677afaSXin Li default: 91*ba677afaSXin Li return fmt.Errorf("unrecognized PackageOriginator type %v", subkey) 92*ba677afaSXin Li } 93*ba677afaSXin Li parser.pkg.PackageOriginator = originator 94*ba677afaSXin Li case "PackageDownloadLocation": 95*ba677afaSXin Li parser.pkg.PackageDownloadLocation = value 96*ba677afaSXin Li case "FilesAnalyzed": 97*ba677afaSXin Li parser.pkg.IsFilesAnalyzedTagPresent = true 98*ba677afaSXin Li if value == "false" { 99*ba677afaSXin Li parser.pkg.FilesAnalyzed = false 100*ba677afaSXin Li } else if value == "true" { 101*ba677afaSXin Li parser.pkg.FilesAnalyzed = true 102*ba677afaSXin Li } 103*ba677afaSXin Li case "PackageVerificationCode": 104*ba677afaSXin Li parser.pkg.PackageVerificationCode = extractCodeAndExcludes(value) 105*ba677afaSXin Li case "PackageChecksum": 106*ba677afaSXin Li subkey, subvalue, err := extractSubs(value) 107*ba677afaSXin Li if err != nil { 108*ba677afaSXin Li return err 109*ba677afaSXin Li } 110*ba677afaSXin Li if parser.pkg.PackageChecksums == nil { 111*ba677afaSXin Li parser.pkg.PackageChecksums = []common.Checksum{} 112*ba677afaSXin Li } 113*ba677afaSXin Li switch common.ChecksumAlgorithm(subkey) { 114*ba677afaSXin Li case common.SHA1, 115*ba677afaSXin Li common.SHA224, 116*ba677afaSXin Li common.SHA256, 117*ba677afaSXin Li common.SHA384, 118*ba677afaSXin Li common.SHA512, 119*ba677afaSXin Li common.MD2, 120*ba677afaSXin Li common.MD4, 121*ba677afaSXin Li common.MD5, 122*ba677afaSXin Li common.MD6, 123*ba677afaSXin Li common.SHA3_256, 124*ba677afaSXin Li common.SHA3_384, 125*ba677afaSXin Li common.SHA3_512, 126*ba677afaSXin Li common.BLAKE2b_256, 127*ba677afaSXin Li common.BLAKE2b_384, 128*ba677afaSXin Li common.BLAKE2b_512, 129*ba677afaSXin Li common.BLAKE3, 130*ba677afaSXin Li common.ADLER32: 131*ba677afaSXin Li algorithm := common.ChecksumAlgorithm(subkey) 132*ba677afaSXin Li parser.pkg.PackageChecksums = append(parser.pkg.PackageChecksums, common.Checksum{Algorithm: algorithm, Value: subvalue}) 133*ba677afaSXin Li default: 134*ba677afaSXin Li return fmt.Errorf("got unknown checksum type %s", subkey) 135*ba677afaSXin Li } 136*ba677afaSXin Li case "PackageHomePage": 137*ba677afaSXin Li parser.pkg.PackageHomePage = value 138*ba677afaSXin Li case "PackageSourceInfo": 139*ba677afaSXin Li parser.pkg.PackageSourceInfo = value 140*ba677afaSXin Li case "PackageLicenseConcluded": 141*ba677afaSXin Li parser.pkg.PackageLicenseConcluded = value 142*ba677afaSXin Li case "PackageLicenseInfoFromFiles": 143*ba677afaSXin Li parser.pkg.PackageLicenseInfoFromFiles = append(parser.pkg.PackageLicenseInfoFromFiles, value) 144*ba677afaSXin Li case "PackageLicenseDeclared": 145*ba677afaSXin Li parser.pkg.PackageLicenseDeclared = value 146*ba677afaSXin Li case "PackageLicenseComments": 147*ba677afaSXin Li parser.pkg.PackageLicenseComments = value 148*ba677afaSXin Li case "PackageCopyrightText": 149*ba677afaSXin Li parser.pkg.PackageCopyrightText = value 150*ba677afaSXin Li case "PackageSummary": 151*ba677afaSXin Li parser.pkg.PackageSummary = value 152*ba677afaSXin Li case "PackageDescription": 153*ba677afaSXin Li parser.pkg.PackageDescription = value 154*ba677afaSXin Li case "PackageComment": 155*ba677afaSXin Li parser.pkg.PackageComment = value 156*ba677afaSXin Li case "PrimaryPackagePurpose": 157*ba677afaSXin Li parser.pkg.PrimaryPackagePurpose = value 158*ba677afaSXin Li case "ReleaseDate": 159*ba677afaSXin Li parser.pkg.ReleaseDate = value 160*ba677afaSXin Li case "BuiltDate": 161*ba677afaSXin Li parser.pkg.BuiltDate = value 162*ba677afaSXin Li case "ValidUntilDate": 163*ba677afaSXin Li parser.pkg.ValidUntilDate = value 164*ba677afaSXin Li case "PackageAttributionText": 165*ba677afaSXin Li parser.pkg.PackageAttributionTexts = append(parser.pkg.PackageAttributionTexts, value) 166*ba677afaSXin Li case "ExternalRef": 167*ba677afaSXin Li parser.pkgExtRef = &v2_3.PackageExternalReference{} 168*ba677afaSXin Li parser.pkg.PackageExternalReferences = append(parser.pkg.PackageExternalReferences, parser.pkgExtRef) 169*ba677afaSXin Li category, refType, locator, err := extractPackageExternalReference(value) 170*ba677afaSXin Li if err != nil { 171*ba677afaSXin Li return err 172*ba677afaSXin Li } 173*ba677afaSXin Li parser.pkgExtRef.Category = category 174*ba677afaSXin Li parser.pkgExtRef.RefType = refType 175*ba677afaSXin Li parser.pkgExtRef.Locator = locator 176*ba677afaSXin Li case "ExternalRefComment": 177*ba677afaSXin Li if parser.pkgExtRef == nil { 178*ba677afaSXin Li return fmt.Errorf("no current ExternalRef found") 179*ba677afaSXin Li } 180*ba677afaSXin Li parser.pkgExtRef.ExternalRefComment = value 181*ba677afaSXin Li // now, expire pkgExtRef anyway because it can have at most one comment 182*ba677afaSXin Li parser.pkgExtRef = nil 183*ba677afaSXin Li // for relationship tags, pass along but don't change state 184*ba677afaSXin Li case "Relationship": 185*ba677afaSXin Li parser.rln = &v2_3.Relationship{} 186*ba677afaSXin Li parser.doc.Relationships = append(parser.doc.Relationships, parser.rln) 187*ba677afaSXin Li return parser.parsePairForRelationship2_3(tag, value) 188*ba677afaSXin Li case "RelationshipComment": 189*ba677afaSXin Li return parser.parsePairForRelationship2_3(tag, value) 190*ba677afaSXin Li // for annotation tags, pass along but don't change state 191*ba677afaSXin Li case "Annotator": 192*ba677afaSXin Li parser.ann = &v2_3.Annotation{} 193*ba677afaSXin Li parser.doc.Annotations = append(parser.doc.Annotations, parser.ann) 194*ba677afaSXin Li return parser.parsePairForAnnotation2_3(tag, value) 195*ba677afaSXin Li case "AnnotationDate": 196*ba677afaSXin Li return parser.parsePairForAnnotation2_3(tag, value) 197*ba677afaSXin Li case "AnnotationType": 198*ba677afaSXin Li return parser.parsePairForAnnotation2_3(tag, value) 199*ba677afaSXin Li case "SPDXREF": 200*ba677afaSXin Li return parser.parsePairForAnnotation2_3(tag, value) 201*ba677afaSXin Li case "AnnotationComment": 202*ba677afaSXin Li return parser.parsePairForAnnotation2_3(tag, value) 203*ba677afaSXin Li // tag for going on to review section (DEPRECATED) 204*ba677afaSXin Li case "Reviewer": 205*ba677afaSXin Li parser.st = psReview2_3 206*ba677afaSXin Li return parser.parsePairFromReview2_3(tag, value) 207*ba677afaSXin Li default: 208*ba677afaSXin Li return fmt.Errorf("received unknown tag %v in Package section", tag) 209*ba677afaSXin Li } 210*ba677afaSXin Li 211*ba677afaSXin Li return nil 212*ba677afaSXin Li} 213*ba677afaSXin Li 214*ba677afaSXin Li// ===== Helper functions ===== 215*ba677afaSXin Li 216*ba677afaSXin Lifunc extractCodeAndExcludes(value string) *common.PackageVerificationCode { 217*ba677afaSXin Li // FIXME this should probably be done using regular expressions instead 218*ba677afaSXin Li // split by paren + word "excludes:" 219*ba677afaSXin Li sp := strings.SplitN(value, "(excludes:", 2) 220*ba677afaSXin Li if len(sp) < 2 { 221*ba677afaSXin Li // not found; return the whole string as just the code 222*ba677afaSXin Li return &common.PackageVerificationCode{Value: value, ExcludedFiles: []string{}} 223*ba677afaSXin Li } 224*ba677afaSXin Li 225*ba677afaSXin Li // if we're here, code is in first part and excludes filename is in 226*ba677afaSXin Li // second part, with trailing paren 227*ba677afaSXin Li code := strings.TrimSpace(sp[0]) 228*ba677afaSXin Li parsedSp := strings.SplitN(sp[1], ")", 2) 229*ba677afaSXin Li fileName := strings.TrimSpace(parsedSp[0]) 230*ba677afaSXin Li return &common.PackageVerificationCode{Value: code, ExcludedFiles: []string{fileName}} 231*ba677afaSXin Li} 232*ba677afaSXin Li 233*ba677afaSXin Lifunc extractPackageExternalReference(value string) (string, string, string, error) { 234*ba677afaSXin Li sp := strings.Split(value, " ") 235*ba677afaSXin Li // remove any that are just whitespace 236*ba677afaSXin Li keepSp := []string{} 237*ba677afaSXin Li for _, s := range sp { 238*ba677afaSXin Li ss := strings.TrimSpace(s) 239*ba677afaSXin Li if ss != "" { 240*ba677afaSXin Li keepSp = append(keepSp, ss) 241*ba677afaSXin Li } 242*ba677afaSXin Li } 243*ba677afaSXin Li // now, should have 3 items and should be able to map them 244*ba677afaSXin Li if len(keepSp) != 3 { 245*ba677afaSXin Li return "", "", "", fmt.Errorf("expected 3 elements, got %d", len(keepSp)) 246*ba677afaSXin Li } 247*ba677afaSXin Li return keepSp[0], keepSp[1], keepSp[2], nil 248*ba677afaSXin Li} 249