1*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 2*ba677afaSXin Li 3*ba677afaSXin Lipackage parser2v2 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) 11*ba677afaSXin Li 12*ba677afaSXin Li// used to extract key / value from embedded substrings 13*ba677afaSXin Li// returns subkey, subvalue, nil if no error, or "", "", error otherwise 14*ba677afaSXin Lifunc extractSubs(value string) (string, string, error) { 15*ba677afaSXin Li // parse the value to see if it's a valid subvalue format 16*ba677afaSXin Li sp := strings.SplitN(value, ":", 2) 17*ba677afaSXin Li if len(sp) == 1 { 18*ba677afaSXin Li return "", "", fmt.Errorf("invalid subvalue format for %s (no colon found)", value) 19*ba677afaSXin Li } 20*ba677afaSXin Li 21*ba677afaSXin Li subkey := strings.TrimSpace(sp[0]) 22*ba677afaSXin Li subvalue := strings.TrimSpace(sp[1]) 23*ba677afaSXin Li 24*ba677afaSXin Li return subkey, subvalue, nil 25*ba677afaSXin Li} 26*ba677afaSXin Li 27*ba677afaSXin Li// used to extract DocumentRef and SPDXRef values from an SPDX Identifier 28*ba677afaSXin Li// which can point either to this document or to a different one 29*ba677afaSXin Lifunc extractDocElementID(value string) (common.DocElementID, error) { 30*ba677afaSXin Li docRefID := "" 31*ba677afaSXin Li idStr := value 32*ba677afaSXin Li 33*ba677afaSXin Li // check prefix to see if it's a DocumentRef ID 34*ba677afaSXin Li if strings.HasPrefix(idStr, "DocumentRef-") { 35*ba677afaSXin Li // extract the part that comes between "DocumentRef-" and ":" 36*ba677afaSXin Li strs := strings.Split(idStr, ":") 37*ba677afaSXin Li // should be exactly two, part before and part after 38*ba677afaSXin Li if len(strs) < 2 { 39*ba677afaSXin Li return common.DocElementID{}, fmt.Errorf("no colon found although DocumentRef- prefix present") 40*ba677afaSXin Li } 41*ba677afaSXin Li if len(strs) > 2 { 42*ba677afaSXin Li return common.DocElementID{}, fmt.Errorf("more than one colon found") 43*ba677afaSXin Li } 44*ba677afaSXin Li 45*ba677afaSXin Li // trim the prefix and confirm non-empty 46*ba677afaSXin Li docRefID = strings.TrimPrefix(strs[0], "DocumentRef-") 47*ba677afaSXin Li if docRefID == "" { 48*ba677afaSXin Li return common.DocElementID{}, fmt.Errorf("document identifier has nothing after prefix") 49*ba677afaSXin Li } 50*ba677afaSXin Li // and use remainder for element ID parsing 51*ba677afaSXin Li idStr = strs[1] 52*ba677afaSXin Li } 53*ba677afaSXin Li 54*ba677afaSXin Li // check prefix to confirm it's got the right prefix for element IDs 55*ba677afaSXin Li if !strings.HasPrefix(idStr, "SPDXRef-") { 56*ba677afaSXin Li return common.DocElementID{}, fmt.Errorf("missing SPDXRef- prefix for element identifier") 57*ba677afaSXin Li } 58*ba677afaSXin Li 59*ba677afaSXin Li // make sure no colons are present 60*ba677afaSXin Li if strings.Contains(idStr, ":") { 61*ba677afaSXin Li // we know this means there was no DocumentRef- prefix, because 62*ba677afaSXin Li // we would have handled multiple colons above if it was 63*ba677afaSXin Li return common.DocElementID{}, fmt.Errorf("invalid colon in element identifier") 64*ba677afaSXin Li } 65*ba677afaSXin Li 66*ba677afaSXin Li // trim the prefix and confirm non-empty 67*ba677afaSXin Li eltRefID := strings.TrimPrefix(idStr, "SPDXRef-") 68*ba677afaSXin Li if eltRefID == "" { 69*ba677afaSXin Li return common.DocElementID{}, fmt.Errorf("element identifier has nothing after prefix") 70*ba677afaSXin Li } 71*ba677afaSXin Li 72*ba677afaSXin Li // we're good 73*ba677afaSXin Li return common.DocElementID{DocumentRefID: docRefID, ElementRefID: common.ElementID(eltRefID)}, nil 74*ba677afaSXin Li} 75*ba677afaSXin Li 76*ba677afaSXin Li// used to extract SPDXRef values from an SPDX Identifier, OR "special" strings 77*ba677afaSXin Li// from a specified set of permitted values. The primary use case for this is 78*ba677afaSXin Li// the right-hand side of Relationships, where beginning in SPDX 2.2 the values 79*ba677afaSXin Li// "NONE" and "NOASSERTION" are permitted. If the value does not match one of 80*ba677afaSXin Li// the specified permitted values, it will fall back to the ordinary 81*ba677afaSXin Li// DocElementID extractor. 82*ba677afaSXin Lifunc extractDocElementSpecial(value string, permittedSpecial []string) (common.DocElementID, error) { 83*ba677afaSXin Li // check value against special set first 84*ba677afaSXin Li for _, sp := range permittedSpecial { 85*ba677afaSXin Li if sp == value { 86*ba677afaSXin Li return common.DocElementID{SpecialID: sp}, nil 87*ba677afaSXin Li } 88*ba677afaSXin Li } 89*ba677afaSXin Li // not found, fall back to regular search 90*ba677afaSXin Li return extractDocElementID(value) 91*ba677afaSXin Li} 92*ba677afaSXin Li 93*ba677afaSXin Li// used to extract SPDXRef values only from an SPDX Identifier which can point 94*ba677afaSXin Li// to this document only. Use extractDocElementID for parsing IDs that can 95*ba677afaSXin Li// refer either to this document or a different one. 96*ba677afaSXin Lifunc extractElementID(value string) (common.ElementID, error) { 97*ba677afaSXin Li // check prefix to confirm it's got the right prefix for element IDs 98*ba677afaSXin Li if !strings.HasPrefix(value, "SPDXRef-") { 99*ba677afaSXin Li return common.ElementID(""), fmt.Errorf("missing SPDXRef- prefix for element identifier") 100*ba677afaSXin Li } 101*ba677afaSXin Li 102*ba677afaSXin Li // make sure no colons are present 103*ba677afaSXin Li if strings.Contains(value, ":") { 104*ba677afaSXin Li return common.ElementID(""), fmt.Errorf("invalid colon in element identifier") 105*ba677afaSXin Li } 106*ba677afaSXin Li 107*ba677afaSXin Li // trim the prefix and confirm non-empty 108*ba677afaSXin Li eltRefID := strings.TrimPrefix(value, "SPDXRef-") 109*ba677afaSXin Li if eltRefID == "" { 110*ba677afaSXin Li return common.ElementID(""), fmt.Errorf("element identifier has nothing after prefix") 111*ba677afaSXin Li } 112*ba677afaSXin Li 113*ba677afaSXin Li // we're good 114*ba677afaSXin Li return common.ElementID(eltRefID), nil 115*ba677afaSXin Li} 116