xref: /aosp_15_r20/external/spdx-tools/tvloader/parser2v1/parser.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// Package parser2v1 contains functions to read, load and parse
2// SPDX tag-value files.
3// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
4package parser2v1
5
6import (
7	"fmt"
8
9	"github.com/spdx/tools-golang/spdx/common"
10	"github.com/spdx/tools-golang/spdx/v2_1"
11	"github.com/spdx/tools-golang/tvloader/reader"
12)
13
14// ParseTagValues takes a list of (tag, value) pairs, parses it and returns
15// a pointer to a parsed SPDX Document.
16func ParseTagValues(tvs []reader.TagValuePair) (*v2_1.Document, error) {
17	parser := tvParser2_1{}
18	for _, tv := range tvs {
19		err := parser.parsePair2_1(tv.Tag, tv.Value)
20		if err != nil {
21			return nil, err
22		}
23	}
24	if parser.file != nil && parser.file.FileSPDXIdentifier == nullSpdxElementId2_1 {
25		return nil, fmt.Errorf("file with FileName %s does not have SPDX identifier", parser.file.FileName)
26	}
27	if parser.pkg != nil && parser.pkg.PackageSPDXIdentifier == nullSpdxElementId2_1 {
28		return nil, fmt.Errorf("package with PackageName %s does not have SPDX identifier", parser.pkg.PackageName)
29	}
30
31	return parser.doc, nil
32}
33
34func (parser *tvParser2_1) parsePair2_1(tag string, value string) error {
35	switch parser.st {
36	case psStart2_1:
37		return parser.parsePairFromStart2_1(tag, value)
38	case psCreationInfo2_1:
39		return parser.parsePairFromCreationInfo2_1(tag, value)
40	case psPackage2_1:
41		return parser.parsePairFromPackage2_1(tag, value)
42	case psFile2_1:
43		return parser.parsePairFromFile2_1(tag, value)
44	case psSnippet2_1:
45		return parser.parsePairFromSnippet2_1(tag, value)
46	case psOtherLicense2_1:
47		return parser.parsePairFromOtherLicense2_1(tag, value)
48	case psReview2_1:
49		return parser.parsePairFromReview2_1(tag, value)
50	default:
51		return fmt.Errorf("parser state %v not recognized when parsing (%s, %s)", parser.st, tag, value)
52	}
53}
54
55func (parser *tvParser2_1) parsePairFromStart2_1(tag string, value string) error {
56	// fail if not in Start parser state
57	if parser.st != psStart2_1 {
58		return fmt.Errorf("got invalid state %v in parsePairFromStart2_1", parser.st)
59	}
60
61	// create an SPDX Document data struct if we don't have one already
62	if parser.doc == nil {
63		parser.doc = &v2_1.Document{
64			ExternalDocumentReferences: []v2_1.ExternalDocumentRef{},
65		}
66	}
67
68	switch tag {
69	case "SPDXVersion":
70		parser.doc.SPDXVersion = value
71	case "DataLicense":
72		parser.doc.DataLicense = value
73	case "SPDXID":
74		eID, err := extractElementID(value)
75		if err != nil {
76			return err
77		}
78		parser.doc.SPDXIdentifier = eID
79	case "DocumentName":
80		parser.doc.DocumentName = value
81	case "DocumentNamespace":
82		parser.doc.DocumentNamespace = value
83	case "ExternalDocumentRef":
84		documentRefID, uri, alg, checksum, err := extractExternalDocumentReference(value)
85		if err != nil {
86			return err
87		}
88		edr := v2_1.ExternalDocumentRef{
89			DocumentRefID: documentRefID,
90			URI:           uri,
91			Checksum:      common.Checksum{Algorithm: common.ChecksumAlgorithm(alg), Value: checksum},
92		}
93		parser.doc.ExternalDocumentReferences = append(parser.doc.ExternalDocumentReferences, edr)
94	case "DocumentComment":
95		parser.doc.DocumentComment = value
96	default:
97		// move to Creation Info parser state
98		parser.st = psCreationInfo2_1
99		return parser.parsePairFromCreationInfo2_1(tag, value)
100	}
101
102	return nil
103}
104