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  }