You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
1.3 KiB
75 lines
1.3 KiB
package stringprep |
|
|
|
import ( |
|
"golang.org/x/text/unicode/norm" |
|
) |
|
|
|
// Profile represents a stringprep profile. |
|
type Profile struct { |
|
Mappings []Mapping |
|
Normalize bool |
|
Prohibits []Set |
|
CheckBiDi bool |
|
} |
|
|
|
var errProhibited = "prohibited character" |
|
|
|
// Prepare transforms an input string to an output string following |
|
// the rules defined in the profile as defined by RFC-3454. |
|
func (p Profile) Prepare(s string) (string, error) { |
|
// Optimistically, assume output will be same length as input |
|
temp := make([]rune, 0, len(s)) |
|
|
|
// Apply maps |
|
for _, r := range s { |
|
rs, ok := p.applyMaps(r) |
|
if ok { |
|
temp = append(temp, rs...) |
|
} else { |
|
temp = append(temp, r) |
|
} |
|
} |
|
|
|
// Normalize |
|
var out string |
|
if p.Normalize { |
|
out = norm.NFKC.String(string(temp)) |
|
} else { |
|
out = string(temp) |
|
} |
|
|
|
// Check prohibited |
|
for _, r := range out { |
|
if p.runeIsProhibited(r) { |
|
return "", Error{Msg: errProhibited, Rune: r} |
|
} |
|
} |
|
|
|
// Check BiDi allowed |
|
if p.CheckBiDi { |
|
if err := passesBiDiRules(out); err != nil { |
|
return "", err |
|
} |
|
} |
|
|
|
return out, nil |
|
} |
|
|
|
func (p Profile) applyMaps(r rune) ([]rune, bool) { |
|
for _, m := range p.Mappings { |
|
rs, ok := m.Map(r) |
|
if ok { |
|
return rs, true |
|
} |
|
} |
|
return nil, false |
|
} |
|
|
|
func (p Profile) runeIsProhibited(r rune) bool { |
|
for _, s := range p.Prohibits { |
|
if s.Contains(r) { |
|
return true |
|
} |
|
} |
|
return false |
|
}
|
|
|