mirror of https://github.com/tidwall/tile38.git
76 lines
1.3 KiB
Go
76 lines
1.3 KiB
Go
|
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
|
||
|
}
|