156 lines
2.8 KiB
Go
156 lines
2.8 KiB
Go
package searcher
|
|
|
|
import (
|
|
"errors"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
func patternToTarget(pattern string) ([]byte, error) {
|
|
if len(pattern) > 3 && pattern[0] == '0' {
|
|
switch pattern[1] {
|
|
case 'x', 'X':
|
|
return decodeHexLiteral(pattern)
|
|
case 'b', 'B':
|
|
return decodeBinLiteral(pattern)
|
|
}
|
|
}
|
|
return unescapePattern(pattern), nil
|
|
}
|
|
|
|
func decodeHexLiteral(pattern string) ([]byte, error) {
|
|
bs := make([]byte, 0, len(pattern)/2+1)
|
|
var c byte
|
|
var lower bool
|
|
for i := 2; i < len(pattern); i++ {
|
|
if !isHex(pattern[i]) {
|
|
return nil, errors.New("invalid hex pattern: " + pattern)
|
|
}
|
|
c = c<<4 | hexToDigit(pattern[i])
|
|
if lower {
|
|
bs = append(bs, c)
|
|
c = 0
|
|
}
|
|
lower = !lower
|
|
}
|
|
if lower {
|
|
bs = append(bs, c<<4)
|
|
}
|
|
return bs, nil
|
|
}
|
|
|
|
func decodeBinLiteral(pattern string) ([]byte, error) {
|
|
bs := make([]byte, 0, len(pattern)/16+1)
|
|
var c byte
|
|
var bits int
|
|
for i := 2; i < len(pattern); i++ {
|
|
if !isBin(pattern[i]) {
|
|
return nil, errors.New("invalid bin pattern: " + pattern)
|
|
}
|
|
c = c<<1 | hexToDigit(pattern[i])
|
|
bits++
|
|
if bits == 8 {
|
|
bits = 0
|
|
bs = append(bs, c)
|
|
c = 0
|
|
}
|
|
}
|
|
if bits > 0 {
|
|
bs = append(bs, c<<uint(8-bits))
|
|
}
|
|
return bs, nil
|
|
}
|
|
|
|
func unescapePattern(pattern string) []byte {
|
|
var escape bool
|
|
var buf [4]byte
|
|
bs := make([]byte, 0, len(pattern))
|
|
for i := 0; i < len(pattern); i++ {
|
|
b := pattern[i]
|
|
if escape {
|
|
switch b {
|
|
case '0':
|
|
bs = append(bs, 0)
|
|
case 'a':
|
|
bs = append(bs, '\a')
|
|
case 'b':
|
|
bs = append(bs, '\b')
|
|
case 'f':
|
|
bs = append(bs, '\f')
|
|
case 'n':
|
|
bs = append(bs, '\n')
|
|
case 'r':
|
|
bs = append(bs, '\r')
|
|
case 't':
|
|
bs = append(bs, '\t')
|
|
case 'v':
|
|
bs = append(bs, '\v')
|
|
case 'x', 'u', 'U':
|
|
var n int
|
|
switch b {
|
|
case 'x':
|
|
n = 2
|
|
case 'u':
|
|
n = 4
|
|
case 'U':
|
|
n = 8
|
|
}
|
|
appended := true
|
|
var c rune
|
|
if i+n < len(pattern) {
|
|
for k := 1; k <= n; k++ {
|
|
if !isHex(pattern[i+k]) {
|
|
appended = false
|
|
break
|
|
}
|
|
c = c<<4 | rune(hexToDigit(pattern[i+k]))
|
|
}
|
|
if appended {
|
|
if b == 'x' {
|
|
bs = append(bs, byte(c))
|
|
} else {
|
|
n := utf8.EncodeRune(buf[:], c)
|
|
bs = append(bs, buf[:n]...)
|
|
}
|
|
i += n
|
|
}
|
|
}
|
|
if !appended {
|
|
bs = append(bs, b)
|
|
}
|
|
default:
|
|
bs = append(bs, b)
|
|
}
|
|
escape = false
|
|
} else if b == '\\' {
|
|
escape = true
|
|
} else {
|
|
bs = append(bs, b)
|
|
}
|
|
}
|
|
if escape {
|
|
bs = append(bs, '\\')
|
|
}
|
|
return bs
|
|
}
|
|
|
|
func isHex(b byte) bool {
|
|
return '0' <= b && b <= '9' || 'A' <= b && b <= 'F' || 'a' <= b && b <= 'f'
|
|
}
|
|
|
|
func hexToDigit(b byte) byte {
|
|
switch {
|
|
case '0' <= b && b <= '9':
|
|
return b - '0'
|
|
case 'A' <= b && b <= 'F':
|
|
return b - 'A' + 10
|
|
case 'a' <= b && b <= 'f':
|
|
return b - 'a' + 10
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func isBin(b byte) bool {
|
|
return b == '0' || b == '1'
|
|
}
|