pegic/executor/util/encoding.go (116 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 util
import (
"encoding/binary"
"errors"
"fmt"
"strconv"
"strings"
"unicode/utf8"
)
type Encoder interface {
// encode string into a bytes
EncodeAll(string) ([]byte, error)
// decode from bytes to string
DecodeAll([]byte) (string, error)
// String returns name of the encoding.
String() string
}
type utf8Encoder struct {
}
func (*utf8Encoder) EncodeAll(s string) ([]byte, error) {
if !utf8.ValidString(s) {
return nil, errors.New("invalid utf8 string")
}
return []byte(s), nil // go uses utf8 by default.
}
func (*utf8Encoder) DecodeAll(s []byte) (string, error) {
if !utf8.Valid(s) {
return "", errors.New("invalid utf8 bytes")
}
return string(s), nil
}
func (*utf8Encoder) String() string {
return "UTF8"
}
type int32Encoder struct {
}
func (*int32Encoder) EncodeAll(s string) ([]byte, error) {
i, err := strconv.ParseInt(s, 10, 32 /*bits*/)
if err != nil {
return nil, errors.New("invalid INT32")
}
value := make([]byte, 4 /*bytes*/)
binary.BigEndian.PutUint32(value, uint32(i))
return value, nil
}
func (*int32Encoder) DecodeAll(s []byte) (string, error) {
if len(s) != 4 {
return "", fmt.Errorf("bytes is not a valid INT32")
}
i := binary.BigEndian.Uint32(s)
return fmt.Sprint(int32(i)), nil
}
func (*int32Encoder) String() string {
return "INT32"
}
type int64Encoder struct {
}
func (*int64Encoder) EncodeAll(s string) ([]byte, error) {
i, err := strconv.ParseInt(s, 10, 64 /*bits*/)
if err != nil {
return nil, errors.New("invalid INT64")
}
value := make([]byte, 8 /*bytes*/)
binary.BigEndian.PutUint64(value, uint64(i))
return value, nil
}
func (*int64Encoder) DecodeAll(s []byte) (string, error) {
if len(s) != 8 {
return "", fmt.Errorf("bytes is not a valid INT64")
}
i := binary.BigEndian.Uint64(s)
return fmt.Sprint(int64(i)), nil
}
func (*int64Encoder) String() string {
return "INT64"
}
type goBytesEncoder struct {
}
func (*goBytesEncoder) EncodeAll(s string) ([]byte, error) {
bytesInStrList := strings.Split(s, " ")
value := make([]byte, len(bytesInStrList))
for i, byteStr := range bytesInStrList {
b, err := strconv.Atoi(byteStr)
if err != nil || b > 255 || b < 0 { // byte ranges from [0, 255]
return nil, fmt.Errorf("invalid go byte \"%s\"", byteStr)
}
value[i] = byte(b)
}
return value, nil
}
func (*goBytesEncoder) DecodeAll(bytes []byte) (string, error) {
s := make([]string, len(bytes))
for i, c := range bytes {
s[i] = fmt.Sprint(uint8(c))
}
return strings.Join(s, ","), nil
}
func (*goBytesEncoder) String() string {
return "BYTES"
}
// NewEncoder returns nil if the given name is invalid.
func NewEncoder(name string) Encoder {
name = strings.ToLower(name)
switch name {
case "utf8", "utf-8":
return &utf8Encoder{}
case "int32":
return &int32Encoder{}
case "int64":
return &int64Encoder{}
case "bytes":
return &goBytesEncoder{}
case "javabytes":
return &javaBytesEncoder{}
case "asciihex":
return &asciiHexEncoder{}
// TODO(wutao): support hex array, such as 0x37, 0xFF, ...
default:
return nil
}
}