2023-03-06 10:30:19 +01:00
package form
import (
"fmt"
"log"
"net/url"
"reflect"
"strconv"
"time"
)
const (
errArraySize = "Array size of '%d' is larger than the maximum currently set on the decoder of '%d'. To increase this limit please see, SetMaxArraySize(size uint)"
errMissingStartBracket = "Invalid formatting for key '%s' missing '[' bracket"
errMissingEndBracket = "Invalid formatting for key '%s' missing ']' bracket"
)
type decoder struct {
d * Decoder
errs DecodeErrors
dm dataMap
values url . Values
maxKeyLen int
namespace [ ] byte
}
func ( d * decoder ) setError ( namespace [ ] byte , err error ) {
if d . errs == nil {
d . errs = make ( DecodeErrors )
}
d . errs [ string ( namespace ) ] = err
}
func ( d * decoder ) findAlias ( ns string ) * recursiveData {
for i := 0 ; i < len ( d . dm ) ; i ++ {
if d . dm [ i ] . alias == ns {
return d . dm [ i ]
}
}
return nil
}
func ( d * decoder ) parseMapData ( ) {
// already parsed
if len ( d . dm ) > 0 {
return
}
d . maxKeyLen = 0
d . dm = d . dm [ 0 : 0 ]
var i int
var idx int
var l int
var insideBracket bool
var rd * recursiveData
var isNum bool
for k := range d . values {
if len ( k ) > d . maxKeyLen {
d . maxKeyLen = len ( k )
}
for i = 0 ; i < len ( k ) ; i ++ {
switch k [ i ] {
case '[' :
idx = i
insideBracket = true
isNum = true
case ']' :
if ! insideBracket {
log . Panicf ( errMissingStartBracket , k )
}
if rd = d . findAlias ( k [ : idx ] ) ; rd == nil {
l = len ( d . dm ) + 1
if l > cap ( d . dm ) {
dm := make ( dataMap , l )
copy ( dm , d . dm )
rd = new ( recursiveData )
dm [ len ( d . dm ) ] = rd
d . dm = dm
} else {
l = len ( d . dm )
d . dm = d . dm [ : l + 1 ]
rd = d . dm [ l ]
rd . sliceLen = 0
rd . keys = rd . keys [ 0 : 0 ]
}
rd . alias = k [ : idx ]
}
// is map + key
ke := key {
ivalue : - 1 ,
value : k [ idx + 1 : i ] ,
searchValue : k [ idx : i + 1 ] ,
}
// is key is number, most likely array key, keep track of just in case an array/slice.
if isNum {
// no need to check for error, it will always pass
// as we have done the checking to ensure
// the value is a number ahead of time.
2023-07-21 16:22:13 +02:00
var err error
ke . ivalue , err = strconv . Atoi ( ke . value )
if err != nil {
ke . ivalue = - 1
}
2023-03-06 10:30:19 +01:00
if ke . ivalue > rd . sliceLen {
rd . sliceLen = ke . ivalue
}
}
rd . keys = append ( rd . keys , ke )
insideBracket = false
default :
// checking if not a number, 0-9 is 48-57 in byte, see for yourself fmt.Println('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
if insideBracket && ( k [ i ] > 57 || k [ i ] < 48 ) {
isNum = false
}
}
}
// if still inside bracket, that means no ending bracket was ever specified
if insideBracket {
log . Panicf ( errMissingEndBracket , k )
}
}
}
func ( d * decoder ) traverseStruct ( v reflect . Value , typ reflect . Type , namespace [ ] byte ) ( set bool ) {
l := len ( namespace )
first := l == 0
// anonymous structs will still work for caching as the whole definition is stored
// including tags
s , ok := d . d . structCache . Get ( typ )
if ! ok {
s = d . d . structCache . parseStruct ( d . d . mode , v , typ , d . d . tagName )
}
for _ , f := range s . fields {
namespace = namespace [ : l ]
if f . isAnonymous {
if d . setFieldByType ( v . Field ( f . idx ) , namespace , 0 ) {
set = true
}
}
if first {
namespace = append ( namespace , f . name ... )
} else {
namespace = append ( namespace , d . d . namespacePrefix ... )
namespace = append ( namespace , f . name ... )
namespace = append ( namespace , d . d . namespaceSuffix ... )
}
if d . setFieldByType ( v . Field ( f . idx ) , namespace , 0 ) {
set = true
}
}
return
}
func ( d * decoder ) setFieldByType ( current reflect . Value , namespace [ ] byte , idx int ) ( set bool ) {
var err error
v , kind := ExtractType ( current )
arr , ok := d . values [ string ( namespace ) ]
if d . d . customTypeFuncs != nil {
if ok {
if cf , ok := d . d . customTypeFuncs [ v . Type ( ) ] ; ok {
val , err := cf ( arr [ idx : ] )
if err != nil {
d . setError ( namespace , err )
return
}
v . Set ( reflect . ValueOf ( val ) )
set = true
return
}
}
}
switch kind {
case reflect . Interface :
if ! ok || idx == len ( arr ) {
return
}
v . Set ( reflect . ValueOf ( arr [ idx ] ) )
set = true
case reflect . Ptr :
newVal := reflect . New ( v . Type ( ) . Elem ( ) )
if set = d . setFieldByType ( newVal . Elem ( ) , namespace , idx ) ; set {
v . Set ( newVal )
}
case reflect . String :
if ! ok || idx == len ( arr ) {
return
}
v . SetString ( arr [ idx ] )
set = true
case reflect . Uint , reflect . Uint64 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var u64 uint64
if u64 , err = strconv . ParseUint ( arr [ idx ] , 10 , 64 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetUint ( u64 )
set = true
case reflect . Uint8 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var u64 uint64
if u64 , err = strconv . ParseUint ( arr [ idx ] , 10 , 8 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetUint ( u64 )
set = true
case reflect . Uint16 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var u64 uint64
if u64 , err = strconv . ParseUint ( arr [ idx ] , 10 , 16 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetUint ( u64 )
set = true
case reflect . Uint32 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var u64 uint64
if u64 , err = strconv . ParseUint ( arr [ idx ] , 10 , 32 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetUint ( u64 )
set = true
case reflect . Int , reflect . Int64 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var i64 int64
if i64 , err = strconv . ParseInt ( arr [ idx ] , 10 , 64 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetInt ( i64 )
set = true
case reflect . Int8 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var i64 int64
if i64 , err = strconv . ParseInt ( arr [ idx ] , 10 , 8 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetInt ( i64 )
set = true
case reflect . Int16 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var i64 int64
if i64 , err = strconv . ParseInt ( arr [ idx ] , 10 , 16 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetInt ( i64 )
set = true
case reflect . Int32 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var i64 int64
if i64 , err = strconv . ParseInt ( arr [ idx ] , 10 , 32 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetInt ( i64 )
set = true
case reflect . Float32 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var f float64
if f , err = strconv . ParseFloat ( arr [ idx ] , 32 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Float Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetFloat ( f )
set = true
case reflect . Float64 :
if ! ok || idx == len ( arr ) || len ( arr [ idx ] ) == 0 {
return
}
var f float64
if f , err = strconv . ParseFloat ( arr [ idx ] , 64 ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Float Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetFloat ( f )
set = true
case reflect . Bool :
if ! ok || idx == len ( arr ) {
return
}
var b bool
if b , err = parseBool ( arr [ idx ] ) ; err != nil {
d . setError ( namespace , fmt . Errorf ( "Invalid Boolean Value '%s' Type '%v' Namespace '%s'" , arr [ idx ] , v . Type ( ) , string ( namespace ) ) )
return
}
v . SetBool ( b )
set = true
case reflect . Slice :
d . parseMapData ( )
// slice elements could be mixed eg. number and non-numbers Value[0]=[]string{"10"} and Value=[]string{"10","20"}
if ok && len ( arr ) > 0 {
var varr reflect . Value
var ol int
l := len ( arr )
if v . IsNil ( ) {
varr = reflect . MakeSlice ( v . Type ( ) , len ( arr ) , len ( arr ) )
} else {
ol = v . Len ( )
l += ol
if v . Cap ( ) <= l {
varr = reflect . MakeSlice ( v . Type ( ) , l , l )
} else {
// preserve predefined capacity, possibly for reuse after decoding
varr = reflect . MakeSlice ( v . Type ( ) , l , v . Cap ( ) )
}
reflect . Copy ( varr , v )
}
for i := ol ; i < l ; i ++ {
newVal := reflect . New ( v . Type ( ) . Elem ( ) ) . Elem ( )
if d . setFieldByType ( newVal , namespace , i - ol ) {
set = true
varr . Index ( i ) . Set ( newVal )
}
}
v . Set ( varr )
}
// maybe it's an numbered array i.e. Phone[0].Number
if rd := d . findAlias ( string ( namespace ) ) ; rd != nil {
var varr reflect . Value
var kv key
sl := rd . sliceLen + 1
// checking below for maxArraySize, but if array exists and already
// has sufficient capacity allocated then we do not check as the code
// obviously allows a capacity greater than the maxArraySize.
if v . IsNil ( ) {
if sl > d . d . maxArraySize {
d . setError ( namespace , fmt . Errorf ( errArraySize , sl , d . d . maxArraySize ) )
return
}
varr = reflect . MakeSlice ( v . Type ( ) , sl , sl )
} else if v . Len ( ) < sl {
if v . Cap ( ) <= sl {
if sl > d . d . maxArraySize {
d . setError ( namespace , fmt . Errorf ( errArraySize , sl , d . d . maxArraySize ) )
return
}
varr = reflect . MakeSlice ( v . Type ( ) , sl , sl )
} else {
varr = reflect . MakeSlice ( v . Type ( ) , sl , v . Cap ( ) )
}
reflect . Copy ( varr , v )
} else {
varr = v
}
for i := 0 ; i < len ( rd . keys ) ; i ++ {
kv = rd . keys [ i ]
newVal := reflect . New ( varr . Type ( ) . Elem ( ) ) . Elem ( )
if kv . ivalue == - 1 {
d . setError ( namespace , fmt . Errorf ( "invalid slice index '%s'" , kv . value ) )
continue
}
if d . setFieldByType ( newVal , append ( namespace , kv . searchValue ... ) , 0 ) {
set = true
varr . Index ( kv . ivalue ) . Set ( newVal )
}
}
if ! set {
return
}
v . Set ( varr )
}
case reflect . Array :
d . parseMapData ( )
// array elements could be mixed eg. number and non-numbers Value[0]=[]string{"10"} and Value=[]string{"10","20"}
if ok && len ( arr ) > 0 {
var varr reflect . Value
l := len ( arr )
overCapacity := v . Len ( ) < l
if overCapacity {
// more values than array capacity, ignore values over capacity as it's possible some would just want
// to grab the first x number of elements; in the future strict mode logic should return an error
fmt . Println ( "warning number of post form array values is larger than array capacity, ignoring overflow values" )
}
varr = reflect . Indirect ( reflect . New ( reflect . ArrayOf ( v . Len ( ) , v . Type ( ) . Elem ( ) ) ) )
reflect . Copy ( varr , v )
if v . Len ( ) < len ( arr ) {
l = v . Len ( )
}
for i := 0 ; i < l ; i ++ {
newVal := reflect . New ( v . Type ( ) . Elem ( ) ) . Elem ( )
if d . setFieldByType ( newVal , namespace , i ) {
set = true
varr . Index ( i ) . Set ( newVal )
}
}
v . Set ( varr )
}
// maybe it's an numbered array i.e. Phone[0].Number
if rd := d . findAlias ( string ( namespace ) ) ; rd != nil {
var varr reflect . Value
var kv key
overCapacity := rd . sliceLen >= v . Len ( )
if overCapacity {
// more values than array capacity, ignore values over capacity as it's possible some would just want
// to grab the first x number of elements; in the future strict mode logic should return an error
fmt . Println ( "warning number of post form array values is larger than array capacity, ignoring overflow values" )
}
varr = reflect . Indirect ( reflect . New ( reflect . ArrayOf ( v . Len ( ) , v . Type ( ) . Elem ( ) ) ) )
reflect . Copy ( varr , v )
for i := 0 ; i < len ( rd . keys ) ; i ++ {
kv = rd . keys [ i ]
if kv . ivalue >= v . Len ( ) {
continue
}
newVal := reflect . New ( varr . Type ( ) . Elem ( ) ) . Elem ( )
if kv . ivalue == - 1 {
d . setError ( namespace , fmt . Errorf ( "invalid array index '%s'" , kv . value ) )
continue
}
if d . setFieldByType ( newVal , append ( namespace , kv . searchValue ... ) , 0 ) {
set = true
varr . Index ( kv . ivalue ) . Set ( newVal )
}
}
if ! set {
return
}
v . Set ( varr )
}
case reflect . Map :
var rd * recursiveData
d . parseMapData ( )
// no natural map support so skip directly to dm lookup
if rd = d . findAlias ( string ( namespace ) ) ; rd == nil {
return
}
var existing bool
var kv key
var mp reflect . Value
var mk reflect . Value
typ := v . Type ( )
if v . IsNil ( ) {
mp = reflect . MakeMap ( typ )
} else {
existing = true
mp = v
}
for i := 0 ; i < len ( rd . keys ) ; i ++ {
newVal := reflect . New ( typ . Elem ( ) ) . Elem ( )
mk = reflect . New ( typ . Key ( ) ) . Elem ( )
kv = rd . keys [ i ]
if err := d . getMapKey ( kv . value , mk , namespace ) ; err != nil {
d . setError ( namespace , err )
continue
}
if d . setFieldByType ( newVal , append ( namespace , kv . searchValue ... ) , 0 ) {
set = true
mp . SetMapIndex ( mk , newVal )
}
}
if ! set || existing {
return
}
v . Set ( mp )
case reflect . Struct :
typ := v . Type ( )
// if we get here then no custom time function declared so use RFC3339 by default
if typ == timeType {
if ! ok || len ( arr [ idx ] ) == 0 {
return
}
t , err := time . Parse ( time . RFC3339 , arr [ idx ] )
if err != nil {
d . setError ( namespace , err )
}
v . Set ( reflect . ValueOf ( t ) )
set = true
return
}
d . parseMapData ( )
// we must be recursing infinitly...but that's ok we caught it on the very first overun.
if len ( namespace ) > d . maxKeyLen {
return
}
set = d . traverseStruct ( v , typ , namespace )
}
return
}
func ( d * decoder ) getMapKey ( key string , current reflect . Value , namespace [ ] byte ) ( err error ) {
v , kind := ExtractType ( current )
if d . d . customTypeFuncs != nil {
if cf , ok := d . d . customTypeFuncs [ v . Type ( ) ] ; ok {
val , er := cf ( [ ] string { key } )
if er != nil {
err = er
return
}
v . Set ( reflect . ValueOf ( val ) )
return
}
}
switch kind {
case reflect . Interface :
// If interface would have been set on the struct before decoding,
// say to a struct value we would not get here but kind would be struct.
v . Set ( reflect . ValueOf ( key ) )
return
case reflect . Ptr :
newVal := reflect . New ( v . Type ( ) . Elem ( ) )
if err = d . getMapKey ( key , newVal . Elem ( ) , namespace ) ; err == nil {
v . Set ( newVal )
}
case reflect . String :
v . SetString ( key )
case reflect . Uint , reflect . Uint64 :
u64 , e := strconv . ParseUint ( key , 10 , 64 )
if e != nil {
err = fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetUint ( u64 )
case reflect . Uint8 :
u64 , e := strconv . ParseUint ( key , 10 , 8 )
if e != nil {
err = fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetUint ( u64 )
case reflect . Uint16 :
u64 , e := strconv . ParseUint ( key , 10 , 16 )
if e != nil {
err = fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetUint ( u64 )
case reflect . Uint32 :
u64 , e := strconv . ParseUint ( key , 10 , 32 )
if e != nil {
err = fmt . Errorf ( "Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetUint ( u64 )
case reflect . Int , reflect . Int64 :
i64 , e := strconv . ParseInt ( key , 10 , 64 )
if e != nil {
err = fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetInt ( i64 )
case reflect . Int8 :
i64 , e := strconv . ParseInt ( key , 10 , 8 )
if e != nil {
err = fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetInt ( i64 )
case reflect . Int16 :
i64 , e := strconv . ParseInt ( key , 10 , 16 )
if e != nil {
err = fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetInt ( i64 )
case reflect . Int32 :
i64 , e := strconv . ParseInt ( key , 10 , 32 )
if e != nil {
err = fmt . Errorf ( "Invalid Integer Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetInt ( i64 )
case reflect . Float32 :
f , e := strconv . ParseFloat ( key , 32 )
if e != nil {
err = fmt . Errorf ( "Invalid Float Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetFloat ( f )
case reflect . Float64 :
f , e := strconv . ParseFloat ( key , 64 )
if e != nil {
err = fmt . Errorf ( "Invalid Float Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetFloat ( f )
case reflect . Bool :
b , e := parseBool ( key )
if e != nil {
err = fmt . Errorf ( "Invalid Boolean Value '%s' Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
return
}
v . SetBool ( b )
default :
err = fmt . Errorf ( "Unsupported Map Key '%s', Type '%v' Namespace '%s'" , key , v . Type ( ) , string ( namespace ) )
}
return
}