package common import ( "encoding/base64" "encoding/json" "reflect" "regexp" "strconv" "strings" "time" Xbadoption "github.com/sagernet/sing-box/common/xray/json/badoption" "github.com/sagernet/sing/common/json/badoption" ) func StringToType[T any](str string) T { var value T v := reflect.ValueOf(&value).Elem() switch any(value).(type) { case badoption.Duration: d, err := time.ParseDuration(str) if err != nil { v.SetInt(StringToType[int64](str)) } else { v.Set(reflect.ValueOf(d)) } return value case badoption.HTTPHeader: headers := badoption.HTTPHeader{} reg := regexp.MustCompile(`^[ \t]*?(\S+?):[ \t]*?(\S+?)[ \t]*?$`) for _, header := range strings.Split(str, "\n") { result := reg.FindStringSubmatch(header) if result != nil { key := result[1] headers[key] = strings.Split(result[2], ",") } } v.Set(reflect.ValueOf(headers)) return value } switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: i, _ := strconv.ParseInt(str, 10, 64) v.SetInt(i) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: i, _ := strconv.ParseUint(str, 10, 64) v.SetUint(i) case reflect.Float32, reflect.Float64: f, _ := strconv.ParseFloat(str, 64) v.SetFloat(f) case reflect.Bool: b, _ := strconv.ParseBool(str) v.SetBool(b) default: panic("unsupported type") } return value } func DecodeBase64URLSafe(content string) (string, error) { s := strings.ReplaceAll(content, " ", "-") s = strings.ReplaceAll(s, "/", "_") s = strings.ReplaceAll(s, "+", "-") s = strings.ReplaceAll(s, "=", "") result, err := base64.RawURLEncoding.DecodeString(s) if err != nil { return content, nil } return string(result), nil } func ParseXHTTPRange(value string) (Xbadoption.Range, error) { result := Xbadoption.Range{} encoded, err := json.Marshal(value) if err != nil { return result, err } return result, result.UnmarshalJSON(encoded) }