-
Notifications
You must be signed in to change notification settings - Fork 0
/
xhex.go
112 lines (98 loc) · 2.91 KB
/
xhex.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright (c) 2020. Temple3x ([email protected])
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package xhex implements hexadecimal encoding and decoding.
// xhex use AVX2 (if has) to accelerate encoding&decoding.
package xhex
import (
"errors"
"fmt"
)
const hextable = "0123456789abcdef"
// Encode encodes src into (2 * len(src)) bytes of dst.
//
// Warn:
// dst should have enough space(2 * len(src)),
// and len(src) must not be 0.
func Encode(dst, src []byte) {
encode(dst, src)
}
// Define encode as a variable for reducing branch (test has AVX2 or not),
// see xhex_amd64.go for details.
var encode = func(dst, src []byte) {
encodeBase(dst, src)
}
// encodeBase encodes src byte by byte.
func encodeBase(dst, src []byte) {
j := 0
for _, v := range src {
dst[j] = hextable[v>>4]
dst[j+1] = hextable[v&0x0f]
j += 2
}
}
// ErrLength reports an attempt to decode an odd-length input
// using Decode or DecodeString.
// The stream-based Decoder returns io.ErrUnexpectedEOF instead of ErrLength.
var ErrLength = errors.New("encoding/hex: odd length hex string")
// InvalidByteError values describe errors resulting from an invalid byte in a hex string.
type InvalidByteError byte
func (e InvalidByteError) Error() string {
return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
}
// Decode decodes src into len(src)/2 bytes.
//
// Decode expects that src contains only hexadecimal
// characters and that src has even length.
func Decode(dst, src []byte) error {
return decode(dst, src)
}
var decode = func(dst, src []byte) error {
return decodeBase(dst, src)
}
func decodeBase(dst, src []byte) error {
i, j := 0, 1
for ; j < len(src); j += 2 {
a, ok := fromHexChar(src[j-1])
if !ok {
return InvalidByteError(src[j-1])
}
b, ok := fromHexChar(src[j])
if !ok {
return InvalidByteError(src[j])
}
dst[i] = (a << 4) | b
i++
}
if len(src)%2 == 1 {
// Check for invalid char before reporting bad length,
// since the invalid char (if present) is an earlier problem.
if _, ok := fromHexChar(src[j-1]); !ok {
return InvalidByteError(src[j-1])
}
return ErrLength
}
return nil
}
// fromHexChar converts a hex character into its value and a success flag.
func fromHexChar(c byte) (byte, bool) {
switch {
case '0' <= c && c <= '9':
return c - '0', true
case 'a' <= c && c <= 'f':
return c - 'a' + 10, true
case 'A' <= c && c <= 'F':
return c - 'A' + 10, true
}
return 0, false
}