github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/decoder/uint.go (about) 1 package decoder 2 3 import ( 4 "fmt" 5 "reflect" 6 "unsafe" 7 8 "github.com/trim21/go-phpserialize/internal/errors" 9 "github.com/trim21/go-phpserialize/internal/runtime" 10 ) 11 12 type uintDecoder struct { 13 typ *runtime.Type 14 kind reflect.Kind 15 op func(unsafe.Pointer, uint64) 16 structName string 17 fieldName string 18 } 19 20 func newUintDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, uint64)) *uintDecoder { 21 return &uintDecoder{ 22 typ: typ, 23 kind: typ.Kind(), 24 op: op, 25 structName: structName, 26 fieldName: fieldName, 27 } 28 } 29 30 func (d *uintDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError { 31 return &errors.UnmarshalTypeError{ 32 Value: fmt.Sprintf("number %s", string(buf)), 33 Type: runtime.RType2Type(d.typ), 34 Offset: offset, 35 } 36 } 37 38 var ( 39 pow10u64 = [...]uint64{ 40 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 41 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 42 } 43 pow10u64Len = len(pow10u64) 44 ) 45 46 func (d *uintDecoder) parseUint(b []byte) (uint64, error) { 47 maxDigit := len(b) 48 if maxDigit > pow10u64Len { 49 return 0, fmt.Errorf("invalid length of number") 50 } 51 sum := uint64(0) 52 for i := 0; i < maxDigit; i++ { 53 c := uint64(b[i]) - 48 54 digitValue := pow10u64[maxDigit-i-1] 55 sum += c * digitValue 56 } 57 return sum, nil 58 } 59 60 func (d *uintDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { 61 b := (*sliceHeader)(unsafe.Pointer(&buf)).data 62 if char(b, cursor) != 'i' { 63 return nil, cursor, errors.ErrExpected("int", cursor) 64 } 65 66 cursor++ 67 if char(b, cursor) != ':' { 68 return nil, cursor, errors.ErrExpected("int sep ':'", cursor) 69 } 70 cursor++ 71 72 switch char(b, cursor) { 73 case '0': 74 cursor++ 75 if char(b, cursor) != ';' { 76 return nil, cursor, errors.ErrExpected("';' end int", cursor) 77 } 78 return numZeroBuf, cursor + 1, nil 79 case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': 80 start := cursor 81 cursor++ 82 for numTable[char(b, cursor)] { 83 cursor++ 84 } 85 if char(b, cursor) != ';' { 86 return nil, cursor, errors.ErrExpected("';' end int", cursor) 87 } 88 num := buf[start:cursor] 89 return num, cursor + 1, nil 90 case 'N': 91 if err := validateNull(buf, cursor); err != nil { 92 return nil, 0, err 93 } 94 cursor += 2 95 return nil, cursor, nil 96 default: 97 return nil, 0, d.typeError([]byte{char(b, cursor)}, cursor) 98 } 99 } 100 101 func (d *uintDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { 102 bytes, c, err := d.decodeByte(ctx.Buf, cursor) 103 if err != nil { 104 return 0, err 105 } 106 if bytes == nil { 107 return c, nil 108 } 109 cursor = c 110 111 return d.processBytes(bytes, cursor, p) 112 } 113 114 func (d *uintDecoder) processBytes(bytes []byte, cursor int64, p unsafe.Pointer) (int64, error) { 115 u64, err := d.parseUint(bytes) 116 if err != nil { 117 return 0, d.typeError(bytes, cursor) 118 } 119 switch d.kind { 120 case reflect.Uint8: 121 if (1 << 8) <= u64 { 122 return 0, d.typeError(bytes, cursor) 123 } 124 case reflect.Uint16: 125 if (1 << 16) <= u64 { 126 return 0, d.typeError(bytes, cursor) 127 } 128 case reflect.Uint32: 129 if (1 << 32) <= u64 { 130 return 0, d.typeError(bytes, cursor) 131 } 132 } 133 d.op(p, u64) 134 return cursor, nil 135 }