diff options
Diffstat (limited to 'tvloader/parser2v2/parse_creation_info.go')
-rw-r--r-- | tvloader/parser2v2/parse_creation_info.go | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/tvloader/parser2v2/parse_creation_info.go b/tvloader/parser2v2/parse_creation_info.go new file mode 100644 index 0000000..da258bd --- /dev/null +++ b/tvloader/parser2v2/parse_creation_info.go @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +package parser2v2 + +import ( + "fmt" + "strings" + + "github.com/spdx/tools-golang/spdx/common" + "github.com/spdx/tools-golang/spdx/v2_2" +) + +func (parser *tvParser2_2) parsePairFromCreationInfo2_2(tag string, value string) error { + // fail if not in Creation Info parser state + if parser.st != psCreationInfo2_2 { + return fmt.Errorf("got invalid state %v in parsePairFromCreationInfo2_2", parser.st) + } + + // create an SPDX Creation Info data struct if we don't have one already + if parser.doc.CreationInfo == nil { + parser.doc.CreationInfo = &v2_2.CreationInfo{} + } + + ci := parser.doc.CreationInfo + switch tag { + case "LicenseListVersion": + ci.LicenseListVersion = value + case "Creator": + subkey, subvalue, err := extractSubs(value) + if err != nil { + return err + } + + creator := common.Creator{Creator: subvalue} + switch subkey { + case "Person", "Organization", "Tool": + creator.CreatorType = subkey + default: + return fmt.Errorf("unrecognized Creator type %v", subkey) + } + + ci.Creators = append(ci.Creators, creator) + case "Created": + ci.Created = value + case "CreatorComment": + ci.CreatorComment = value + + // tag for going on to package section + case "PackageName": + // error if last file does not have an identifier + // this may be a null case: can we ever have a "last file" in + // the "creation info" state? should go on to "file" state + // even when parsing unpackaged files. + if parser.file != nil && parser.file.FileSPDXIdentifier == nullSpdxElementId2_2 { + return fmt.Errorf("file with FileName %s does not have SPDX identifier", parser.file.FileName) + } + parser.st = psPackage2_2 + parser.pkg = &v2_2.Package{ + FilesAnalyzed: true, + IsFilesAnalyzedTagPresent: false, + } + return parser.parsePairFromPackage2_2(tag, value) + // tag for going on to _unpackaged_ file section + case "FileName": + // leave pkg as nil, so that packages will be placed in Files + parser.st = psFile2_2 + parser.pkg = nil + return parser.parsePairFromFile2_2(tag, value) + // tag for going on to other license section + case "LicenseID": + parser.st = psOtherLicense2_2 + return parser.parsePairFromOtherLicense2_2(tag, value) + // tag for going on to review section (DEPRECATED) + case "Reviewer": + parser.st = psReview2_2 + return parser.parsePairFromReview2_2(tag, value) + // for relationship tags, pass along but don't change state + case "Relationship": + parser.rln = &v2_2.Relationship{} + parser.doc.Relationships = append(parser.doc.Relationships, parser.rln) + return parser.parsePairForRelationship2_2(tag, value) + case "RelationshipComment": + return parser.parsePairForRelationship2_2(tag, value) + // for annotation tags, pass along but don't change state + case "Annotator": + parser.ann = &v2_2.Annotation{} + parser.doc.Annotations = append(parser.doc.Annotations, parser.ann) + return parser.parsePairForAnnotation2_2(tag, value) + case "AnnotationDate": + return parser.parsePairForAnnotation2_2(tag, value) + case "AnnotationType": + return parser.parsePairForAnnotation2_2(tag, value) + case "SPDXREF": + return parser.parsePairForAnnotation2_2(tag, value) + case "AnnotationComment": + return parser.parsePairForAnnotation2_2(tag, value) + default: + return fmt.Errorf("received unknown tag %v in CreationInfo section", tag) + } + + return nil +} + +// ===== Helper functions ===== + +func extractExternalDocumentReference(value string) (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) + } + } + + var documentRefID, uri, alg, checksum string + + // now, should have 4 items (or 3, if Alg and Checksum were joined) + // and should be able to map them + if len(keepSp) == 4 { + documentRefID = keepSp[0] + uri = keepSp[1] + alg = keepSp[2] + // check that colon is present for alg, and remove it + if !strings.HasSuffix(alg, ":") { + return "", "", "", "", fmt.Errorf("algorithm does not end with colon") + } + alg = strings.TrimSuffix(alg, ":") + checksum = keepSp[3] + } else if len(keepSp) == 3 { + documentRefID = keepSp[0] + uri = keepSp[1] + // split on colon into alg and checksum + parts := strings.SplitN(keepSp[2], ":", 2) + if len(parts) != 2 { + return "", "", "", "", fmt.Errorf("missing colon separator between algorithm and checksum") + } + alg = parts[0] + checksum = parts[1] + } else { + return "", "", "", "", fmt.Errorf("expected 4 elements, got %d", len(keepSp)) + } + + // additionally, we should be able to parse the first element as a + // DocumentRef- ID string, and we should remove that prefix + if !strings.HasPrefix(documentRefID, "DocumentRef-") { + return "", "", "", "", fmt.Errorf("expected first element to have DocumentRef- prefix") + } + documentRefID = strings.TrimPrefix(documentRefID, "DocumentRef-") + if documentRefID == "" { + return "", "", "", "", fmt.Errorf("document identifier has nothing after prefix") + } + + return documentRefID, uri, alg, checksum, nil +} |