unplugged-system/external/spdx-tools/tvloader/parser2v1/parse_creation_info.go

157 lines
4.9 KiB
Go

// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
package parser2v1
import (
"fmt"
"strings"
"github.com/spdx/tools-golang/spdx/common"
"github.com/spdx/tools-golang/spdx/v2_1"
)
func (parser *tvParser2_1) parsePairFromCreationInfo2_1(tag string, value string) error {
// fail if not in Creation Info parser state
if parser.st != psCreationInfo2_1 {
return fmt.Errorf("got invalid state %v in parsePairFromCreationInfo2_1", 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_1.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_1 {
return fmt.Errorf("file with FileName %s does not have SPDX identifier", parser.file.FileName)
}
parser.st = psPackage2_1
parser.pkg = &v2_1.Package{
FilesAnalyzed: true,
IsFilesAnalyzedTagPresent: false,
}
return parser.parsePairFromPackage2_1(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_1
parser.pkg = nil
return parser.parsePairFromFile2_1(tag, value)
// tag for going on to other license section
case "LicenseID":
parser.st = psOtherLicense2_1
return parser.parsePairFromOtherLicense2_1(tag, value)
// tag for going on to review section (DEPRECATED)
case "Reviewer":
parser.st = psReview2_1
return parser.parsePairFromReview2_1(tag, value)
// for relationship tags, pass along but don't change state
case "Relationship":
parser.rln = &v2_1.Relationship{}
parser.doc.Relationships = append(parser.doc.Relationships, parser.rln)
return parser.parsePairForRelationship2_1(tag, value)
case "RelationshipComment":
return parser.parsePairForRelationship2_1(tag, value)
// for annotation tags, pass along but don't change state
case "Annotator":
parser.ann = &v2_1.Annotation{}
parser.doc.Annotations = append(parser.doc.Annotations, parser.ann)
return parser.parsePairForAnnotation2_1(tag, value)
case "AnnotationDate":
return parser.parsePairForAnnotation2_1(tag, value)
case "AnnotationType":
return parser.parsePairForAnnotation2_1(tag, value)
case "SPDXREF":
return parser.parsePairForAnnotation2_1(tag, value)
case "AnnotationComment":
return parser.parsePairForAnnotation2_1(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
}