...

Source file src/github.com/json-iterator/go/extra/fuzzy_decoder.go

Documentation: github.com/json-iterator/go/extra

     1  package extra
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  	"math"
     7  	"reflect"
     8  	"strings"
     9  	"unsafe"
    10  
    11  	"github.com/json-iterator/go"
    12  	"github.com/modern-go/reflect2"
    13  )
    14  
    15  const maxUint = ^uint(0)
    16  const maxInt = int(maxUint >> 1)
    17  const minInt = -maxInt - 1
    18  
    19  // RegisterFuzzyDecoders decode input from PHP with tolerance.
    20  // It will handle string/number auto conversation, and treat empty [] as empty struct.
    21  func RegisterFuzzyDecoders() {
    22  	jsoniter.RegisterExtension(&tolerateEmptyArrayExtension{})
    23  	jsoniter.RegisterTypeDecoder("string", &fuzzyStringDecoder{})
    24  	jsoniter.RegisterTypeDecoder("float32", &fuzzyFloat32Decoder{})
    25  	jsoniter.RegisterTypeDecoder("float64", &fuzzyFloat64Decoder{})
    26  	jsoniter.RegisterTypeDecoder("int", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    27  		if isFloat {
    28  			val := iter.ReadFloat64()
    29  			if val > float64(maxInt) || val < float64(minInt) {
    30  				iter.ReportError("fuzzy decode int", "exceed range")
    31  				return
    32  			}
    33  			*((*int)(ptr)) = int(val)
    34  		} else {
    35  			*((*int)(ptr)) = iter.ReadInt()
    36  		}
    37  	}})
    38  	jsoniter.RegisterTypeDecoder("uint", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    39  		if isFloat {
    40  			val := iter.ReadFloat64()
    41  			if val > float64(maxUint) || val < 0 {
    42  				iter.ReportError("fuzzy decode uint", "exceed range")
    43  				return
    44  			}
    45  			*((*uint)(ptr)) = uint(val)
    46  		} else {
    47  			*((*uint)(ptr)) = iter.ReadUint()
    48  		}
    49  	}})
    50  	jsoniter.RegisterTypeDecoder("int8", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    51  		if isFloat {
    52  			val := iter.ReadFloat64()
    53  			if val > float64(math.MaxInt8) || val < float64(math.MinInt8) {
    54  				iter.ReportError("fuzzy decode int8", "exceed range")
    55  				return
    56  			}
    57  			*((*int8)(ptr)) = int8(val)
    58  		} else {
    59  			*((*int8)(ptr)) = iter.ReadInt8()
    60  		}
    61  	}})
    62  	jsoniter.RegisterTypeDecoder("uint8", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    63  		if isFloat {
    64  			val := iter.ReadFloat64()
    65  			if val > float64(math.MaxUint8) || val < 0 {
    66  				iter.ReportError("fuzzy decode uint8", "exceed range")
    67  				return
    68  			}
    69  			*((*uint8)(ptr)) = uint8(val)
    70  		} else {
    71  			*((*uint8)(ptr)) = iter.ReadUint8()
    72  		}
    73  	}})
    74  	jsoniter.RegisterTypeDecoder("int16", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    75  		if isFloat {
    76  			val := iter.ReadFloat64()
    77  			if val > float64(math.MaxInt16) || val < float64(math.MinInt16) {
    78  				iter.ReportError("fuzzy decode int16", "exceed range")
    79  				return
    80  			}
    81  			*((*int16)(ptr)) = int16(val)
    82  		} else {
    83  			*((*int16)(ptr)) = iter.ReadInt16()
    84  		}
    85  	}})
    86  	jsoniter.RegisterTypeDecoder("uint16", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    87  		if isFloat {
    88  			val := iter.ReadFloat64()
    89  			if val > float64(math.MaxUint16) || val < 0 {
    90  				iter.ReportError("fuzzy decode uint16", "exceed range")
    91  				return
    92  			}
    93  			*((*uint16)(ptr)) = uint16(val)
    94  		} else {
    95  			*((*uint16)(ptr)) = iter.ReadUint16()
    96  		}
    97  	}})
    98  	jsoniter.RegisterTypeDecoder("int32", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    99  		if isFloat {
   100  			val := iter.ReadFloat64()
   101  			if val > float64(math.MaxInt32) || val < float64(math.MinInt32) {
   102  				iter.ReportError("fuzzy decode int32", "exceed range")
   103  				return
   104  			}
   105  			*((*int32)(ptr)) = int32(val)
   106  		} else {
   107  			*((*int32)(ptr)) = iter.ReadInt32()
   108  		}
   109  	}})
   110  	jsoniter.RegisterTypeDecoder("uint32", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   111  		if isFloat {
   112  			val := iter.ReadFloat64()
   113  			if val > float64(math.MaxUint32) || val < 0 {
   114  				iter.ReportError("fuzzy decode uint32", "exceed range")
   115  				return
   116  			}
   117  			*((*uint32)(ptr)) = uint32(val)
   118  		} else {
   119  			*((*uint32)(ptr)) = iter.ReadUint32()
   120  		}
   121  	}})
   122  	jsoniter.RegisterTypeDecoder("int64", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   123  		if isFloat {
   124  			val := iter.ReadFloat64()
   125  			if val > float64(math.MaxInt64) || val < float64(math.MinInt64) {
   126  				iter.ReportError("fuzzy decode int64", "exceed range")
   127  				return
   128  			}
   129  			*((*int64)(ptr)) = int64(val)
   130  		} else {
   131  			*((*int64)(ptr)) = iter.ReadInt64()
   132  		}
   133  	}})
   134  	jsoniter.RegisterTypeDecoder("uint64", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   135  		if isFloat {
   136  			val := iter.ReadFloat64()
   137  			if val > float64(math.MaxUint64) || val < 0 {
   138  				iter.ReportError("fuzzy decode uint64", "exceed range")
   139  				return
   140  			}
   141  			*((*uint64)(ptr)) = uint64(val)
   142  		} else {
   143  			*((*uint64)(ptr)) = iter.ReadUint64()
   144  		}
   145  	}})
   146  }
   147  
   148  type tolerateEmptyArrayExtension struct {
   149  	jsoniter.DummyExtension
   150  }
   151  
   152  func (extension *tolerateEmptyArrayExtension) DecorateDecoder(typ reflect2.Type, decoder jsoniter.ValDecoder) jsoniter.ValDecoder {
   153  	if typ.Kind() == reflect.Struct || typ.Kind() == reflect.Map {
   154  		return &tolerateEmptyArrayDecoder{decoder}
   155  	}
   156  	return decoder
   157  }
   158  
   159  type tolerateEmptyArrayDecoder struct {
   160  	valDecoder jsoniter.ValDecoder
   161  }
   162  
   163  func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   164  	if iter.WhatIsNext() == jsoniter.ArrayValue {
   165  		iter.Skip()
   166  		newIter := iter.Pool().BorrowIterator([]byte("{}"))
   167  		defer iter.Pool().ReturnIterator(newIter)
   168  		decoder.valDecoder.Decode(ptr, newIter)
   169  	} else {
   170  		decoder.valDecoder.Decode(ptr, iter)
   171  	}
   172  }
   173  
   174  type fuzzyStringDecoder struct {
   175  }
   176  
   177  func (decoder *fuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   178  	valueType := iter.WhatIsNext()
   179  	switch valueType {
   180  	case jsoniter.NumberValue:
   181  		var number json.Number
   182  		iter.ReadVal(&number)
   183  		*((*string)(ptr)) = string(number)
   184  	case jsoniter.StringValue:
   185  		*((*string)(ptr)) = iter.ReadString()
   186  	case jsoniter.NilValue:
   187  		iter.Skip()
   188  		*((*string)(ptr)) = ""
   189  	default:
   190  		iter.ReportError("fuzzyStringDecoder", "not number or string")
   191  	}
   192  }
   193  
   194  type fuzzyIntegerDecoder struct {
   195  	fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator)
   196  }
   197  
   198  func (decoder *fuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   199  	valueType := iter.WhatIsNext()
   200  	var str string
   201  	switch valueType {
   202  	case jsoniter.NumberValue:
   203  		var number json.Number
   204  		iter.ReadVal(&number)
   205  		str = string(number)
   206  	case jsoniter.StringValue:
   207  		str = iter.ReadString()
   208  	case jsoniter.BoolValue:
   209  		if iter.ReadBool() {
   210  			str = "1"
   211  		} else {
   212  			str = "0"
   213  		}
   214  	case jsoniter.NilValue:
   215  		iter.Skip()
   216  		str = "0"
   217  	default:
   218  		iter.ReportError("fuzzyIntegerDecoder", "not number or string")
   219  	}
   220  	if len(str) == 0 {
   221  		str = "0"
   222  	}
   223  	newIter := iter.Pool().BorrowIterator([]byte(str))
   224  	defer iter.Pool().ReturnIterator(newIter)
   225  	isFloat := strings.IndexByte(str, '.') != -1
   226  	decoder.fun(isFloat, ptr, newIter)
   227  	if newIter.Error != nil && newIter.Error != io.EOF {
   228  		iter.Error = newIter.Error
   229  	}
   230  }
   231  
   232  type fuzzyFloat32Decoder struct {
   233  }
   234  
   235  func (decoder *fuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   236  	valueType := iter.WhatIsNext()
   237  	var str string
   238  	switch valueType {
   239  	case jsoniter.NumberValue:
   240  		*((*float32)(ptr)) = iter.ReadFloat32()
   241  	case jsoniter.StringValue:
   242  		str = iter.ReadString()
   243  		newIter := iter.Pool().BorrowIterator([]byte(str))
   244  		defer iter.Pool().ReturnIterator(newIter)
   245  		*((*float32)(ptr)) = newIter.ReadFloat32()
   246  		if newIter.Error != nil && newIter.Error != io.EOF {
   247  			iter.Error = newIter.Error
   248  		}
   249  	case jsoniter.BoolValue:
   250  		// support bool to float32
   251  		if iter.ReadBool() {
   252  			*((*float32)(ptr)) = 1
   253  		} else {
   254  			*((*float32)(ptr)) = 0
   255  		}
   256  	case jsoniter.NilValue:
   257  		iter.Skip()
   258  		*((*float32)(ptr)) = 0
   259  	default:
   260  		iter.ReportError("fuzzyFloat32Decoder", "not number or string")
   261  	}
   262  }
   263  
   264  type fuzzyFloat64Decoder struct {
   265  }
   266  
   267  func (decoder *fuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   268  	valueType := iter.WhatIsNext()
   269  	var str string
   270  	switch valueType {
   271  	case jsoniter.NumberValue:
   272  		*((*float64)(ptr)) = iter.ReadFloat64()
   273  	case jsoniter.StringValue:
   274  		str = iter.ReadString()
   275  		newIter := iter.Pool().BorrowIterator([]byte(str))
   276  		defer iter.Pool().ReturnIterator(newIter)
   277  		*((*float64)(ptr)) = newIter.ReadFloat64()
   278  		if newIter.Error != nil && newIter.Error != io.EOF {
   279  			iter.Error = newIter.Error
   280  		}
   281  	case jsoniter.BoolValue:
   282  		// support bool to float64
   283  		if iter.ReadBool() {
   284  			*((*float64)(ptr)) = 1
   285  		} else {
   286  			*((*float64)(ptr)) = 0
   287  		}
   288  	case jsoniter.NilValue:
   289  		iter.Skip()
   290  		*((*float64)(ptr)) = 0
   291  	default:
   292  		iter.ReportError("fuzzyFloat64Decoder", "not number or string")
   293  	}
   294  }
   295  

View as plain text