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  }