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