forked from TrueCloudLab/rclone
lib/encoder: add string rendering and parsing for encodings
This commit is contained in:
parent
1ba5e99152
commit
0a5c83ece1
2 changed files with 166 additions and 0 deletions
|
@ -16,6 +16,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
@ -32,6 +33,7 @@ const (
|
|||
)
|
||||
|
||||
// NB keep the tests in fstests/fstests/fstests.go FsEncoding up to date with this
|
||||
// NB keep the aliases up to date below also
|
||||
|
||||
// Possible flags for the MultiEncoder
|
||||
const (
|
||||
|
@ -99,6 +101,114 @@ type Encoder interface {
|
|||
// character classes
|
||||
type MultiEncoder uint
|
||||
|
||||
// Aliases maps encodings to names and vice versa
|
||||
var (
|
||||
encodingToName = map[MultiEncoder]string{}
|
||||
nameToEncoding = map[string]MultiEncoder{}
|
||||
)
|
||||
|
||||
// alias adds an alias for MultiEncoder.String() and MultiEncoder.Set()
|
||||
func alias(name string, mask MultiEncoder) {
|
||||
nameToEncoding[name] = mask
|
||||
// don't overwrite existing reverse translations
|
||||
if _, ok := encodingToName[mask]; !ok {
|
||||
encodingToName[mask] = name
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
alias("None", EncodeZero)
|
||||
alias("Slash", EncodeSlash)
|
||||
alias("LtGt", EncodeLtGt)
|
||||
alias("DoubleQuote", EncodeDoubleQuote)
|
||||
alias("SingleQuote", EncodeSingleQuote)
|
||||
alias("BackQuote", EncodeBackQuote)
|
||||
alias("Dollar", EncodeDollar)
|
||||
alias("Colon", EncodeColon)
|
||||
alias("Question", EncodeQuestion)
|
||||
alias("Asterisk", EncodeAsterisk)
|
||||
alias("Pipe", EncodePipe)
|
||||
alias("Hash", EncodeHash)
|
||||
alias("Percent", EncodePercent)
|
||||
alias("BackSlash", EncodeBackSlash)
|
||||
alias("CrLf", EncodeCrLf)
|
||||
alias("Del", EncodeDel)
|
||||
alias("Ctl", EncodeCtl)
|
||||
alias("LeftSpace", EncodeLeftSpace)
|
||||
alias("LeftPeriod", EncodeLeftPeriod)
|
||||
alias("LeftTilde", EncodeLeftTilde)
|
||||
alias("LeftCrLfHtVt", EncodeLeftCrLfHtVt)
|
||||
alias("RightSpace", EncodeRightSpace)
|
||||
alias("RightPeriod", EncodeRightPeriod)
|
||||
alias("RightCrLfHtVt", EncodeRightCrLfHtVt)
|
||||
alias("InvalidUtf8", EncodeInvalidUtf8)
|
||||
alias("Dot", EncodeDot)
|
||||
}
|
||||
|
||||
// validStrings returns all the valid MultiEncoder strings
|
||||
func validStrings() string {
|
||||
var out []string
|
||||
for k := range nameToEncoding {
|
||||
out = append(out, k)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return strings.Join(out, ", ")
|
||||
}
|
||||
|
||||
// String converts the MultiEncoder into text
|
||||
func (mask MultiEncoder) String() string {
|
||||
// See if there is an exact translation - if so return that
|
||||
if name, ok := encodingToName[mask]; ok {
|
||||
return name
|
||||
}
|
||||
var out []string
|
||||
// Otherwise decompose bit by bit
|
||||
for bit := MultiEncoder(1); bit != 0; bit *= 2 {
|
||||
if (mask & bit) != 0 {
|
||||
if name, ok := encodingToName[bit]; ok {
|
||||
out = append(out, name)
|
||||
} else {
|
||||
out = append(out, fmt.Sprintf("0x%X", uint(bit)))
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
|
||||
// Set converts a string into a MultiEncoder
|
||||
func (mask *MultiEncoder) Set(in string) error {
|
||||
var out MultiEncoder
|
||||
parts := strings.Split(in, ",")
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if bits, ok := nameToEncoding[part]; ok {
|
||||
out |= bits
|
||||
} else {
|
||||
i, err := strconv.ParseInt(part, 0, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad encoding %q: possible values are: %s", part, validStrings())
|
||||
}
|
||||
out |= MultiEncoder(i)
|
||||
}
|
||||
}
|
||||
*mask = out
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns a textual type of the MultiEncoder to satsify the pflag.Value interface
|
||||
func (mask MultiEncoder) Type() string {
|
||||
return "Encoding"
|
||||
}
|
||||
|
||||
// Scan implements the fmt.Scanner interface
|
||||
func (mask *MultiEncoder) Scan(s fmt.ScanState, ch rune) error {
|
||||
token, err := s.Token(true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mask.Set(string(token))
|
||||
}
|
||||
|
||||
// Encode takes a raw name and substitutes any reserved characters and
|
||||
// patterns in it
|
||||
func (mask MultiEncoder) Encode(in string) string {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue