upd: essential/file updated
helper codec updated
This commit is contained in:
parent
c61eb950fb
commit
ebc7dc3800
@ -0,0 +1,689 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Description
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name:
|
||||
| - Codec
|
||||
|
|
||||
| Purpose:
|
||||
| - Provide unified encoding and decoding capabilities using Base8,
|
||||
| Base10, Base16, Base32, Base64, and Sqids with centralized
|
||||
| validation, operation dispatching, transformation handling,
|
||||
| and standardized result generation.
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Instruction
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Guideline:
|
||||
| - Use the utility to encode input data using the selected codec format.
|
||||
| - Use the utility to decode input data using the selected codec format.
|
||||
| - Configure the codec format using base8, base10, base16, base32,
|
||||
| base64, or sqids.
|
||||
| - Provide input data as a string or []byte.
|
||||
| - Configure charset and salt transformations when required.
|
||||
| - Configure lower or upper output casing when required.
|
||||
| - Configure minimum output length for Sqids encoding.
|
||||
| - Configure length for deterministic Sqids decoding.
|
||||
|
|
||||
| Example:
|
||||
| - ObrimCodec("encode", map[string]any{
|
||||
| "format": "base64",
|
||||
| "data": "hello",
|
||||
| })
|
||||
|
|
||||
| - ObrimCodec("decode", map[string]any{
|
||||
| "format": "base64",
|
||||
| "data": "aGVsbG8=",
|
||||
| })
|
||||
|
|
||||
| - ObrimCodec("encode", map[string]any{
|
||||
| "format": "sqids",
|
||||
| "data": "12345",
|
||||
| "charset": "abcdefghijklmnopqrstuvwxyz",
|
||||
| "salt": "example",
|
||||
| "length": 8,
|
||||
| })
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Contributor:
|
||||
| - Rajon Ahmed
|
||||
| - Blockonite
|
||||
|
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
package codec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/sqids/sqids-go"
|
||||
)
|
||||
|
||||
const (
|
||||
obrimCodecTypeEncode = "encode"
|
||||
obrimCodecTypeDecode = "decode"
|
||||
|
||||
obrimCodecFormatBase8 = "base8"
|
||||
obrimCodecFormatBase10 = "base10"
|
||||
obrimCodecFormatBase16 = "base16"
|
||||
obrimCodecFormatBase32 = "base32"
|
||||
obrimCodecFormatBase64 = "base64"
|
||||
obrimCodecFormatSqids = "sqids"
|
||||
|
||||
obrimCodecCaseLower = "lower"
|
||||
obrimCodecCaseUpper = "upper"
|
||||
|
||||
obrimCodecSuccessEncoded = "SUCCESS_ENCODED"
|
||||
obrimCodecSuccessDecoded = "SUCCESS_DECODED"
|
||||
|
||||
obrimCodecFailureInvalidType = "FAILURE_INVALID_TYPE"
|
||||
obrimCodecFailureInvalidConfig = "FAILURE_INVALID_CONFIG"
|
||||
obrimCodecFailureInvalidFormat = "FAILURE_INVALID_FORMAT"
|
||||
obrimCodecFailureInvalidData = "FAILURE_INVALID_DATA"
|
||||
obrimCodecFailureInvalidCharset = "FAILURE_INVALID_CHARSET"
|
||||
obrimCodecFailureInvalidSalt = "FAILURE_INVALID_SALT"
|
||||
obrimCodecFailureInvalidCase = "FAILURE_INVALID_CASE"
|
||||
obrimCodecFailureInvalidLength = "FAILURE_INVALID_LENGTH"
|
||||
obrimCodecFailureEncoding = "FAILURE_ENCODING"
|
||||
obrimCodecFailureDecoding = "FAILURE_DECODING"
|
||||
obrimCodecFailureTransformation = "FAILURE_TRANSFORMATION"
|
||||
obrimCodecFailureTransformationReversal = "FAILURE_TRANSFORMATION_REVERSAL"
|
||||
obrimCodecFailureUnsupportedData = "FAILURE_UNSUPPORTED_DATA"
|
||||
obrimCodecFailureSqids = "FAILURE_SQIDS"
|
||||
)
|
||||
|
||||
type obrimCodecConfig struct {
|
||||
format string
|
||||
data []byte
|
||||
charset string
|
||||
salt string
|
||||
caseRule string
|
||||
length int
|
||||
}
|
||||
|
||||
type obrimCodecResult struct {
|
||||
operation string
|
||||
format string
|
||||
value string
|
||||
}
|
||||
|
||||
type obrimCodecOutput struct {
|
||||
Status bool `json:"status"`
|
||||
Code string `json:"code"`
|
||||
Payload *obrimCodecResult `json:"payload"`
|
||||
}
|
||||
|
||||
func ObrimCodec(typ string, config map[string]any) map[string]any {
|
||||
normalized, code := obrimCodecValidateInput(typ, config)
|
||||
if code != "" {
|
||||
return obrimCodecBuildOutput(false, code, nil)
|
||||
}
|
||||
|
||||
value, code := obrimCodecRouteRequest(typ, normalized)
|
||||
if code != "" {
|
||||
return obrimCodecBuildOutput(false, code, nil)
|
||||
}
|
||||
|
||||
if typ == obrimCodecTypeEncode {
|
||||
return obrimCodecBuildOutput(
|
||||
true,
|
||||
obrimCodecSuccessEncoded,
|
||||
&obrimCodecResult{
|
||||
operation: typ,
|
||||
format: normalized.format,
|
||||
value: value,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return obrimCodecBuildOutput(
|
||||
true,
|
||||
obrimCodecSuccessDecoded,
|
||||
&obrimCodecResult{
|
||||
operation: typ,
|
||||
format: normalized.format,
|
||||
value: value,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func obrimCodecValidateInput(typ string, config map[string]any) (obrimCodecConfig, string) {
|
||||
var result obrimCodecConfig
|
||||
|
||||
switch typ {
|
||||
case obrimCodecTypeEncode, obrimCodecTypeDecode:
|
||||
default:
|
||||
return result, obrimCodecFailureInvalidType
|
||||
}
|
||||
|
||||
formatValue, exists := config["format"]
|
||||
if !exists {
|
||||
return result, obrimCodecFailureInvalidConfig
|
||||
}
|
||||
|
||||
format, ok := formatValue.(string)
|
||||
if !ok || format == "" {
|
||||
return result, obrimCodecFailureInvalidFormat
|
||||
}
|
||||
|
||||
switch format {
|
||||
case obrimCodecFormatBase8,
|
||||
obrimCodecFormatBase10,
|
||||
obrimCodecFormatBase16,
|
||||
obrimCodecFormatBase32,
|
||||
obrimCodecFormatBase64,
|
||||
obrimCodecFormatSqids:
|
||||
default:
|
||||
return result, obrimCodecFailureInvalidFormat
|
||||
}
|
||||
|
||||
dataValue, exists := config["data"]
|
||||
if !exists {
|
||||
return result, obrimCodecFailureInvalidData
|
||||
}
|
||||
|
||||
switch value := dataValue.(type) {
|
||||
case string:
|
||||
if value == "" {
|
||||
return result, obrimCodecFailureInvalidData
|
||||
}
|
||||
result.data = []byte(value)
|
||||
case []byte:
|
||||
if len(value) == 0 {
|
||||
return result, obrimCodecFailureInvalidData
|
||||
}
|
||||
result.data = append([]byte(nil), value...)
|
||||
default:
|
||||
return result, obrimCodecFailureUnsupportedData
|
||||
}
|
||||
|
||||
result.format = format
|
||||
|
||||
if charsetValue, exists := config["charset"]; exists {
|
||||
charset, ok := charsetValue.(string)
|
||||
if !ok || charset == "" {
|
||||
return result, obrimCodecFailureInvalidCharset
|
||||
}
|
||||
result.charset = charset
|
||||
}
|
||||
|
||||
if saltValue, exists := config["salt"]; exists {
|
||||
salt, ok := saltValue.(string)
|
||||
if !ok || salt == "" {
|
||||
return result, obrimCodecFailureInvalidSalt
|
||||
}
|
||||
result.salt = salt
|
||||
}
|
||||
|
||||
if caseValue, exists := config["case"]; exists {
|
||||
caseRule, ok := caseValue.(string)
|
||||
if !ok {
|
||||
return result, obrimCodecFailureInvalidCase
|
||||
}
|
||||
|
||||
switch caseRule {
|
||||
case obrimCodecCaseLower, obrimCodecCaseUpper:
|
||||
result.caseRule = caseRule
|
||||
default:
|
||||
return result, obrimCodecFailureInvalidCase
|
||||
}
|
||||
}
|
||||
|
||||
if lengthValue, exists := config["length"]; exists {
|
||||
switch length := lengthValue.(type) {
|
||||
case int:
|
||||
result.length = length
|
||||
case int8:
|
||||
result.length = int(length)
|
||||
case int16:
|
||||
result.length = int(length)
|
||||
case int32:
|
||||
result.length = int(length)
|
||||
case int64:
|
||||
result.length = int(length)
|
||||
case uint:
|
||||
result.length = int(length)
|
||||
case uint8:
|
||||
result.length = int(length)
|
||||
case uint16:
|
||||
result.length = int(length)
|
||||
case uint32:
|
||||
result.length = int(length)
|
||||
case uint64:
|
||||
if uint64(int(length)) != length {
|
||||
return result, obrimCodecFailureInvalidLength
|
||||
}
|
||||
result.length = int(length)
|
||||
case float64:
|
||||
if length != float64(int(length)) {
|
||||
return result, obrimCodecFailureInvalidLength
|
||||
}
|
||||
result.length = int(length)
|
||||
default:
|
||||
return result, obrimCodecFailureInvalidLength
|
||||
}
|
||||
|
||||
if result.length < 0 {
|
||||
return result, obrimCodecFailureInvalidLength
|
||||
}
|
||||
}
|
||||
|
||||
if format == obrimCodecFormatSqids && result.length == 0 {
|
||||
result.length = 0
|
||||
}
|
||||
|
||||
return result, ""
|
||||
}
|
||||
|
||||
func obrimCodecRouteRequest(typ string, config obrimCodecConfig) (string, string) {
|
||||
switch typ {
|
||||
case obrimCodecTypeEncode:
|
||||
return obrimCodecEncode(config)
|
||||
case obrimCodecTypeDecode:
|
||||
return obrimCodecDecode(config)
|
||||
default:
|
||||
return "", obrimCodecFailureInvalidType
|
||||
}
|
||||
}
|
||||
|
||||
func obrimCodecBuildOutput(status bool, code string, payload *obrimCodecResult) map[string]any {
|
||||
if !status {
|
||||
return map[string]any{
|
||||
"status": false,
|
||||
"code": code,
|
||||
"payload": nil,
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"status": true,
|
||||
"code": code,
|
||||
"payload": map[string]any{
|
||||
"operation": payload.operation,
|
||||
"format": payload.format,
|
||||
"value": payload.value,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func obrimCodecEncode(config obrimCodecConfig) (string, string) {
|
||||
data, code := obrimCodecApplyEncodeTransformations(config.data, config)
|
||||
if code != "" {
|
||||
return "", code
|
||||
}
|
||||
|
||||
var (
|
||||
value string
|
||||
err error
|
||||
)
|
||||
|
||||
switch config.format {
|
||||
case obrimCodecFormatBase8:
|
||||
value, err = obrimCodecEncodeBase8(data)
|
||||
case obrimCodecFormatBase10:
|
||||
value, err = obrimCodecEncodeBase10(data)
|
||||
case obrimCodecFormatBase16:
|
||||
value, err = obrimCodecEncodeBase16(data)
|
||||
case obrimCodecFormatBase32:
|
||||
value, err = obrimCodecEncodeBase32(data)
|
||||
case obrimCodecFormatBase64:
|
||||
value, err = obrimCodecEncodeBase64(data)
|
||||
case obrimCodecFormatSqids:
|
||||
value, err = obrimCodecEncodeSqids(data, config)
|
||||
default:
|
||||
return "", obrimCodecFailureInvalidFormat
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if config.format == obrimCodecFormatSqids {
|
||||
return "", obrimCodecFailureSqids
|
||||
}
|
||||
return "", obrimCodecFailureEncoding
|
||||
}
|
||||
|
||||
value = obrimCodecApplyCase(value, config.caseRule)
|
||||
return value, ""
|
||||
}
|
||||
|
||||
func obrimCodecDecode(config obrimCodecConfig) (string, string) {
|
||||
data := append([]byte(nil), config.data...)
|
||||
|
||||
var err error
|
||||
var value []byte
|
||||
|
||||
switch config.format {
|
||||
case obrimCodecFormatBase8:
|
||||
value, err = obrimCodecDecodeBase8(string(data))
|
||||
case obrimCodecFormatBase10:
|
||||
value, err = obrimCodecDecodeBase10(string(data))
|
||||
case obrimCodecFormatBase16:
|
||||
value, err = obrimCodecDecodeBase16(string(data))
|
||||
case obrimCodecFormatBase32:
|
||||
value, err = obrimCodecDecodeBase32(string(data))
|
||||
case obrimCodecFormatBase64:
|
||||
value, err = obrimCodecDecodeBase64(string(data))
|
||||
case obrimCodecFormatSqids:
|
||||
value, err = obrimCodecDecodeSqids(string(data), config)
|
||||
default:
|
||||
return "", obrimCodecFailureInvalidFormat
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if config.format == obrimCodecFormatSqids {
|
||||
return "", obrimCodecFailureSqids
|
||||
}
|
||||
return "", obrimCodecFailureDecoding
|
||||
}
|
||||
|
||||
value, err = obrimCodecApplyDecodeTransformations(value, config)
|
||||
if err != nil {
|
||||
return "", obrimCodecFailureTransformationReversal
|
||||
}
|
||||
|
||||
return string(value), ""
|
||||
}
|
||||
|
||||
func obrimCodecEncodeBase8(data []byte) (string, error) {
|
||||
if len(data) == 0 {
|
||||
return "", fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
number := new(big.Int).SetBytes(data)
|
||||
return number.Text(8), nil
|
||||
}
|
||||
|
||||
func obrimCodecEncodeBase10(data []byte) (string, error) {
|
||||
if len(data) == 0 {
|
||||
return "", fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
number := new(big.Int).SetBytes(data)
|
||||
return number.Text(10), nil
|
||||
}
|
||||
|
||||
func obrimCodecEncodeBase16(data []byte) (string, error) {
|
||||
if len(data) == 0 {
|
||||
return "", fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
return hex.EncodeToString(data), nil
|
||||
}
|
||||
|
||||
func obrimCodecEncodeBase32(data []byte) (string, error) {
|
||||
if len(data) == 0 {
|
||||
return "", fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(data), nil
|
||||
}
|
||||
|
||||
func obrimCodecEncodeBase64(data []byte) (string, error) {
|
||||
if len(data) == 0 {
|
||||
return "", fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(data), nil
|
||||
}
|
||||
|
||||
func obrimCodecEncodeSqids(data []byte, config obrimCodecConfig) (string, error) {
|
||||
if len(data) == 0 {
|
||||
return "", fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
number := new(big.Int).SetBytes(data)
|
||||
|
||||
if !number.IsUint64() {
|
||||
return "", fmt.Errorf("sqids input exceeds uint64")
|
||||
}
|
||||
|
||||
options := sqids.Options{}
|
||||
|
||||
if config.charset != "" {
|
||||
options.Alphabet = config.charset
|
||||
}
|
||||
|
||||
if config.length > 0 {
|
||||
options.MinLength = config.length
|
||||
}
|
||||
|
||||
encoder, err := sqids.New(options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encoder.Encode([]uint64{number.Uint64()}), nil
|
||||
}
|
||||
|
||||
func obrimCodecDecodeBase8(data string) ([]byte, error) {
|
||||
data = strings.TrimSpace(data)
|
||||
|
||||
if data == "" {
|
||||
return nil, fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
number := new(big.Int)
|
||||
if _, ok := number.SetString(data, 8); !ok {
|
||||
return nil, fmt.Errorf("invalid base8 value")
|
||||
}
|
||||
|
||||
return obrimCodecBigIntBytes(number), nil
|
||||
}
|
||||
|
||||
func obrimCodecDecodeBase10(data string) ([]byte, error) {
|
||||
data = strings.TrimSpace(data)
|
||||
|
||||
if data == "" {
|
||||
return nil, fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
number := new(big.Int)
|
||||
if _, ok := number.SetString(data, 10); !ok {
|
||||
return nil, fmt.Errorf("invalid base10 value")
|
||||
}
|
||||
|
||||
return obrimCodecBigIntBytes(number), nil
|
||||
}
|
||||
|
||||
func obrimCodecDecodeBase16(data string) ([]byte, error) {
|
||||
data = strings.TrimSpace(data)
|
||||
|
||||
if data == "" {
|
||||
return nil, fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
if len(data)%2 != 0 {
|
||||
data = "0" + data
|
||||
}
|
||||
|
||||
return hex.DecodeString(data)
|
||||
}
|
||||
|
||||
func obrimCodecDecodeBase32(data string) ([]byte, error) {
|
||||
data = strings.TrimSpace(data)
|
||||
|
||||
if data == "" {
|
||||
return nil, fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
padding := len(data) % 8
|
||||
if padding != 0 {
|
||||
data += strings.Repeat("=", 8-padding)
|
||||
}
|
||||
|
||||
return base32.StdEncoding.DecodeString(data)
|
||||
}
|
||||
|
||||
func obrimCodecDecodeBase64(data string) ([]byte, error) {
|
||||
data = strings.TrimSpace(data)
|
||||
|
||||
if data == "" {
|
||||
return nil, fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
return base64.StdEncoding.DecodeString(data)
|
||||
}
|
||||
|
||||
func obrimCodecDecodeSqids(data string, config obrimCodecConfig) ([]byte, error) {
|
||||
if data == "" {
|
||||
return nil, fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
options := sqids.Options{}
|
||||
|
||||
if config.charset != "" {
|
||||
options.Alphabet = config.charset
|
||||
}
|
||||
|
||||
if config.length > 0 {
|
||||
options.MinLength = config.length
|
||||
}
|
||||
|
||||
encoder, err := sqids.New(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
numbers := encoder.Decode(data)
|
||||
if len(numbers) != 1 {
|
||||
return nil, fmt.Errorf("invalid sqids value")
|
||||
}
|
||||
|
||||
number := new(big.Int).SetUint64(numbers[0])
|
||||
return obrimCodecBigIntBytes(number), nil
|
||||
}
|
||||
|
||||
func obrimCodecBigIntBytes(number *big.Int) []byte {
|
||||
if number.Sign() == 0 {
|
||||
return []byte{0}
|
||||
}
|
||||
|
||||
return number.Bytes()
|
||||
}
|
||||
|
||||
func obrimCodecApplyEncodeTransformations(data []byte, config obrimCodecConfig) ([]byte, string) {
|
||||
result := append([]byte(nil), data...)
|
||||
|
||||
if config.salt != "" {
|
||||
result = obrimCodecApplySalt(result, []byte(config.salt))
|
||||
}
|
||||
|
||||
if config.charset != "" && config.format != obrimCodecFormatSqids {
|
||||
transformed, err := obrimCodecApplyCharsetEncode(result, config.charset)
|
||||
if err != nil {
|
||||
return nil, obrimCodecFailureTransformation
|
||||
}
|
||||
result = transformed
|
||||
}
|
||||
|
||||
return result, ""
|
||||
}
|
||||
|
||||
func obrimCodecApplyDecodeTransformations(data []byte, config obrimCodecConfig) ([]byte, error) {
|
||||
result := append([]byte(nil), data...)
|
||||
|
||||
if config.charset != "" && config.format != obrimCodecFormatSqids {
|
||||
transformed, err := obrimCodecApplyCharsetDecode(result, config.charset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = transformed
|
||||
}
|
||||
|
||||
if config.salt != "" {
|
||||
result = obrimCodecApplySalt(result, []byte(config.salt))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func obrimCodecApplyCharsetEncode(data []byte, charset string) ([]byte, error) {
|
||||
charsetBytes := []byte(charset)
|
||||
if len(charsetBytes) < 2 {
|
||||
return nil, fmt.Errorf("charset must contain at least two characters")
|
||||
}
|
||||
|
||||
result := make([]byte, len(data))
|
||||
|
||||
for index, value := range data {
|
||||
result[index] = charsetBytes[int(value)%len(charsetBytes)]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func obrimCodecApplyCharsetDecode(data []byte, charset string) ([]byte, error) {
|
||||
charsetBytes := []byte(charset)
|
||||
if len(charsetBytes) < 2 {
|
||||
return nil, fmt.Errorf("charset must contain at least two characters")
|
||||
}
|
||||
|
||||
reverse := make(map[byte]byte, len(charsetBytes))
|
||||
|
||||
for index, value := range charsetBytes {
|
||||
if _, exists := reverse[value]; exists {
|
||||
return nil, fmt.Errorf("charset contains duplicate characters")
|
||||
}
|
||||
reverse[value] = byte(index)
|
||||
}
|
||||
|
||||
result := make([]byte, len(data))
|
||||
|
||||
for index, value := range data {
|
||||
decoded, exists := reverse[value]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("character not present in charset")
|
||||
}
|
||||
result[index] = decoded
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func obrimCodecApplySalt(data []byte, salt []byte) []byte {
|
||||
if len(salt) == 0 {
|
||||
return data
|
||||
}
|
||||
|
||||
result := make([]byte, len(data))
|
||||
|
||||
for index, value := range data {
|
||||
result[index] = value ^ salt[index%len(salt)]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func obrimCodecApplyCase(value string, caseRule string) string {
|
||||
switch caseRule {
|
||||
case obrimCodecCaseLower:
|
||||
return strings.ToLower(value)
|
||||
case obrimCodecCaseUpper:
|
||||
return strings.ToUpper(value)
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
var _ = bytes.Compare
|
||||
var _ = json.Valid
|
||||
Loading…
Reference in New Issue
Block a user