github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/utils/key.go (about) 1 // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0. 2 3 package utils 4 5 import ( 6 "bytes" 7 "encoding/hex" 8 "fmt" 9 "io" 10 "strings" 11 12 "github.com/pingcap/errors" 13 14 berrors "github.com/pingcap/br/pkg/errors" 15 ) 16 17 // ParseKey parse key by given format. 18 func ParseKey(format, key string) ([]byte, error) { 19 switch format { 20 case "raw": 21 return []byte(key), nil 22 case "escaped": 23 return unescapedKey(key) 24 case "hex": 25 key, err := hex.DecodeString(key) 26 if err != nil { 27 return nil, errors.Trace(err) 28 } 29 return key, nil 30 } 31 return nil, errors.Annotate(berrors.ErrInvalidArgument, "unknown format") 32 } 33 34 // Ref PD: https://github.com/pingcap/pd/blob/master/tools/pd-ctl/pdctl/command/region_command.go#L334 35 func unescapedKey(text string) ([]byte, error) { 36 var buf []byte 37 r := bytes.NewBuffer([]byte(text)) 38 for { 39 c, err := r.ReadByte() 40 if err != nil { 41 if errors.Cause(err) != io.EOF { // nolint:errorlint 42 return nil, errors.Trace(err) 43 } 44 break 45 } 46 if c != '\\' { 47 buf = append(buf, c) 48 continue 49 } 50 n := r.Next(1) 51 if len(n) == 0 { 52 return nil, io.EOF 53 } 54 // See: https://golang.org/ref/spec#Rune_literals 55 if idx := strings.IndexByte(`abfnrtv\'"`, n[0]); idx != -1 { 56 buf = append(buf, []byte("\a\b\f\n\r\t\v\\'\"")[idx]) 57 continue 58 } 59 60 switch n[0] { 61 case 'x': 62 fmt.Sscanf(string(r.Next(2)), "%02x", &c) 63 buf = append(buf, c) 64 default: 65 n = append(n, r.Next(2)...) 66 _, err := fmt.Sscanf(string(n), "%03o", &c) 67 if err != nil { 68 return nil, errors.Trace(err) 69 } 70 buf = append(buf, c) 71 } 72 } 73 return buf, nil 74 } 75 76 // CompareEndKey compared two keys that BOTH represent the EXCLUSIVE ending of some range. An empty end key is the very 77 // end, so an empty key is greater than any other keys. 78 // Please note that this function is not applicable if any one argument is not an EXCLUSIVE ending of a range. 79 func CompareEndKey(a, b []byte) int { 80 if len(a) == 0 { 81 if len(b) == 0 { 82 return 0 83 } 84 return 1 85 } 86 87 if len(b) == 0 { 88 return -1 89 } 90 91 return bytes.Compare(a, b) 92 }